oxlint-plugin-react-doctor 0.9.2-dev.5dc936e → 0.9.2-dev.5f23826
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 +66 -362
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29461,11 +29461,6 @@ const jsCacheStorage = defineRule({
|
|
|
29461
29461
|
});
|
|
29462
29462
|
//#endregion
|
|
29463
29463
|
//#region src/plugin/rules/js-performance/js-combine-iterations.ts
|
|
29464
|
-
const SMALL_ARRAY_NON_MUTATING_METHODS = new Set([
|
|
29465
|
-
...CHAINABLE_ITERATION_METHODS,
|
|
29466
|
-
"find",
|
|
29467
|
-
"some"
|
|
29468
|
-
]);
|
|
29469
29464
|
const isIteratorProducingCall = (callExpression, generatorNamesInFile) => {
|
|
29470
29465
|
const callee = callExpression.callee;
|
|
29471
29466
|
if (isNodeOfType(callee, "MemberExpression")) {
|
|
@@ -29577,34 +29572,21 @@ const isStringSplitRootedChain = (receiverNode) => {
|
|
|
29577
29572
|
return false;
|
|
29578
29573
|
};
|
|
29579
29574
|
const isSmallLiteralArray = (node) => {
|
|
29580
|
-
|
|
29581
|
-
|
|
29582
|
-
|
|
29583
|
-
if (elements.length === 0 || elements.length > 9) return false;
|
|
29575
|
+
if (!isNodeOfType(node, "ArrayExpression")) return false;
|
|
29576
|
+
const elements = node.elements ?? [];
|
|
29577
|
+
if (elements.length === 0 || elements.length > 8) return false;
|
|
29584
29578
|
for (const element of elements) {
|
|
29585
29579
|
if (!element) continue;
|
|
29586
29580
|
if (isNodeOfType(element, "SpreadElement")) return false;
|
|
29587
29581
|
}
|
|
29588
29582
|
return true;
|
|
29589
29583
|
};
|
|
29590
|
-
const
|
|
29591
|
-
const identifierRoot = findTransparentExpressionRoot(identifier);
|
|
29592
|
-
const memberExpression = identifierRoot.parent;
|
|
29593
|
-
if (!isNodeOfType(memberExpression, "MemberExpression") || memberExpression.object !== identifierRoot || !isNodeOfType(memberExpression.property, "Identifier") || !SMALL_ARRAY_NON_MUTATING_METHODS.has(memberExpression.property.name)) return false;
|
|
29594
|
-
const callExpression = memberExpression.parent;
|
|
29595
|
-
return isNodeOfType(callExpression, "CallExpression") && callExpression.callee === memberExpression;
|
|
29596
|
-
};
|
|
29597
|
-
const isSmallLiteralArrayRootedChain = (receiverNode, scopes) => {
|
|
29584
|
+
const isSmallLiteralArrayRootedChain = (receiverNode, smallConstArrayNames) => {
|
|
29598
29585
|
let cursor = receiverNode;
|
|
29599
29586
|
while (cursor) {
|
|
29600
29587
|
cursor = stripParenExpression(cursor);
|
|
29601
29588
|
if (isNodeOfType(cursor, "ArrayExpression")) return isSmallLiteralArray(cursor);
|
|
29602
|
-
if (isNodeOfType(cursor, "Identifier"))
|
|
29603
|
-
const symbol = scopes.symbolFor(cursor);
|
|
29604
|
-
if (!symbol?.initializer || !isSmallLiteralArray(symbol.initializer)) return false;
|
|
29605
|
-
if (!isNodeOfType(symbol.declarationNode, "VariableDeclarator") || !isNodeOfType(symbol.declarationNode.id, "Identifier")) return false;
|
|
29606
|
-
return (symbol.kind === "const" || symbol.kind === "let" || symbol.kind === "var") && symbol.references.every((reference) => reference.flag === "read" && isNonMutatingSmallArrayMethodReference(reference.identifier));
|
|
29607
|
-
}
|
|
29589
|
+
if (isNodeOfType(cursor, "Identifier")) return smallConstArrayNames.has(cursor.name);
|
|
29608
29590
|
if (!isNodeOfType(cursor, "CallExpression")) return false;
|
|
29609
29591
|
if (!isChainPassThroughCall(cursor)) return false;
|
|
29610
29592
|
const nextCallee = cursor.callee;
|
|
@@ -29613,6 +29595,22 @@ const isSmallLiteralArrayRootedChain = (receiverNode, scopes) => {
|
|
|
29613
29595
|
}
|
|
29614
29596
|
return false;
|
|
29615
29597
|
};
|
|
29598
|
+
const collectSmallConstArrayNames = (programNode) => {
|
|
29599
|
+
const names = /* @__PURE__ */ new Set();
|
|
29600
|
+
const statements = programNode.body ?? [];
|
|
29601
|
+
for (const statement of statements) {
|
|
29602
|
+
const declaration = isNodeOfType(statement, "ExportNamedDeclaration") ? statement.declaration : statement;
|
|
29603
|
+
if (!declaration || !isNodeOfType(declaration, "VariableDeclaration")) continue;
|
|
29604
|
+
if (declaration.kind !== "const") continue;
|
|
29605
|
+
for (const declarator of declaration.declarations ?? []) {
|
|
29606
|
+
if (!isNodeOfType(declarator, "VariableDeclarator")) continue;
|
|
29607
|
+
if (!isNodeOfType(declarator.id, "Identifier")) continue;
|
|
29608
|
+
if (!declarator.init || !isSmallLiteralArray(declarator.init)) continue;
|
|
29609
|
+
names.add(declarator.id.name);
|
|
29610
|
+
}
|
|
29611
|
+
}
|
|
29612
|
+
return names;
|
|
29613
|
+
};
|
|
29616
29614
|
const collectGeneratorNames = (programNode) => {
|
|
29617
29615
|
const generatorNames = /* @__PURE__ */ new Set();
|
|
29618
29616
|
walkAst(programNode, (child) => {
|
|
@@ -29633,11 +29631,16 @@ const jsCombineIterations = defineRule({
|
|
|
29633
29631
|
create: (context) => {
|
|
29634
29632
|
let programNode = null;
|
|
29635
29633
|
let generatorNamesInFile = null;
|
|
29634
|
+
let smallConstArrayNames = null;
|
|
29636
29635
|
const coveredChainCalls = /* @__PURE__ */ new WeakSet();
|
|
29637
29636
|
const getGeneratorNamesInFile = () => {
|
|
29638
29637
|
generatorNamesInFile ??= programNode ? collectGeneratorNames(programNode) : /* @__PURE__ */ new Set();
|
|
29639
29638
|
return generatorNamesInFile;
|
|
29640
29639
|
};
|
|
29640
|
+
const getSmallConstArrayNames = () => {
|
|
29641
|
+
smallConstArrayNames ??= programNode ? collectSmallConstArrayNames(programNode) : /* @__PURE__ */ new Set();
|
|
29642
|
+
return smallConstArrayNames;
|
|
29643
|
+
};
|
|
29641
29644
|
return {
|
|
29642
29645
|
Program(node) {
|
|
29643
29646
|
programNode = node;
|
|
@@ -29667,7 +29670,7 @@ const jsCombineIterations = defineRule({
|
|
|
29667
29670
|
if (isTypePredicateArrow(filterArgument)) return;
|
|
29668
29671
|
}
|
|
29669
29672
|
if (isReceiverChainIteratorRooted(innerCall.callee.object, getGeneratorNamesInFile())) return;
|
|
29670
|
-
if (isSmallLiteralArrayRootedChain(innerCall.callee.object,
|
|
29673
|
+
if (isSmallLiteralArrayRootedChain(innerCall.callee.object, getSmallConstArrayNames())) return;
|
|
29671
29674
|
if (isStringSplitRootedChain(innerCall.callee.object)) return;
|
|
29672
29675
|
coveredChainCalls.add(innerCall);
|
|
29673
29676
|
context.report({
|
|
@@ -56087,13 +56090,9 @@ const isInitialOnlyPropName = (propName) => {
|
|
|
56087
56090
|
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);
|
|
56088
56091
|
};
|
|
56089
56092
|
//#endregion
|
|
56090
|
-
//#region src/plugin/utils/nextjs-page-data-export-names.ts
|
|
56091
|
-
const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
|
|
56092
|
-
//#endregion
|
|
56093
56093
|
//#region src/plugin/rules/state-and-effects/no-derived-use-state.ts
|
|
56094
56094
|
const isInitialOnlySeedName = (propName) => isInitialOnlyPropName(propName) || propName === "initial" || propName === "autoFocus" || propName === "autoPlay" || propName === "startOpen" || /^initially[A-Z]/.test(propName) || /Initial([A-Z]|$)/.test(propName);
|
|
56095
56095
|
const SNAPSHOT_STATE_NAME_PATTERN = /^(initial|previous|prev|preserved|saved|original|cached|snapshot|prior|debounced|deferred)([A-Z_]|$)/;
|
|
56096
|
-
const INTERNAL_STATE_NAME_PATTERN = /^(internal|uncontrolled)([A-Z_]|$)/;
|
|
56097
56096
|
const getStateSetterName = (useStateCall) => {
|
|
56098
56097
|
const declarator = useStateCall.parent;
|
|
56099
56098
|
if (!isNodeOfType(declarator, "VariableDeclarator")) return null;
|
|
@@ -56247,6 +56246,7 @@ const isDraftCommittedToParent = (componentFunction, stateValueName, isPropName)
|
|
|
56247
56246
|
});
|
|
56248
56247
|
return isCommitted;
|
|
56249
56248
|
};
|
|
56249
|
+
const NEXTJS_PAGE_DATA_EXPORT_NAMES = new Set(["getServerSideProps", "getStaticProps"]);
|
|
56250
56250
|
const isNextjsDataFetchingPage = (node) => {
|
|
56251
56251
|
const program = findProgramRoot(node);
|
|
56252
56252
|
if (!program) return false;
|
|
@@ -56290,48 +56290,6 @@ const isInRenderScope = (node, componentFunction) => {
|
|
|
56290
56290
|
}
|
|
56291
56291
|
return true;
|
|
56292
56292
|
};
|
|
56293
|
-
const isReferenceToBinding = (reference, bindingIdentifier, context) => {
|
|
56294
|
-
if (!isNodeOfType(reference, "Identifier")) return false;
|
|
56295
|
-
const bindingSymbol = context.scopes.symbolFor(bindingIdentifier);
|
|
56296
|
-
if (!bindingSymbol) return false;
|
|
56297
|
-
return (context.scopes.referenceFor(reference)?.resolvedSymbol)?.id === bindingSymbol.id;
|
|
56298
|
-
};
|
|
56299
|
-
const isControlledPropFallbackExpression = (expression, stateBinding, isPropName, context) => {
|
|
56300
|
-
if (isNodeOfType(expression, "ConditionalExpression")) {
|
|
56301
|
-
const consequent = unwrapInitializerSeed(expression.consequent);
|
|
56302
|
-
const alternate = unwrapInitializerSeed(expression.alternate);
|
|
56303
|
-
return isReferenceToBinding(consequent, stateBinding, context) && isPropDerivedArgument(alternate, isPropName) || isPropDerivedArgument(consequent, isPropName) && isReferenceToBinding(alternate, stateBinding, context);
|
|
56304
|
-
}
|
|
56305
|
-
return isNodeOfType(expression, "LogicalExpression") && expression.operator === "??" && isPropDerivedArgument(unwrapInitializerSeed(expression.left), isPropName) && isReferenceToBinding(unwrapInitializerSeed(expression.right), stateBinding, context);
|
|
56306
|
-
};
|
|
56307
|
-
const isUserEditableControlledFallback = (useStateCall, isPropName, context) => {
|
|
56308
|
-
const declarator = useStateCall.parent;
|
|
56309
|
-
if (!isNodeOfType(declarator, "VariableDeclarator")) return false;
|
|
56310
|
-
if (!isNodeOfType(declarator.id, "ArrayPattern")) return false;
|
|
56311
|
-
const stateBinding = declarator.id.elements?.[0];
|
|
56312
|
-
const setterBinding = declarator.id.elements?.[1];
|
|
56313
|
-
if (!isNodeOfType(stateBinding, "Identifier") || !isNodeOfType(setterBinding, "Identifier")) return false;
|
|
56314
|
-
if (!INTERNAL_STATE_NAME_PATTERN.test(stateBinding.name)) return false;
|
|
56315
|
-
const componentFunction = findEnclosingFunction$1(useStateCall);
|
|
56316
|
-
if (!componentFunction) return false;
|
|
56317
|
-
let hasControlledFallback = false;
|
|
56318
|
-
let hasUserEdit = false;
|
|
56319
|
-
walkAst(componentFunction, (child) => {
|
|
56320
|
-
if (child !== componentFunction && isFunctionLike$1(child)) return false;
|
|
56321
|
-
if (!hasControlledFallback && (isNodeOfType(child, "ConditionalExpression") || isNodeOfType(child, "LogicalExpression")) && isControlledPropFallbackExpression(child, stateBinding, isPropName, context)) hasControlledFallback = true;
|
|
56322
|
-
});
|
|
56323
|
-
walkAst(componentFunction, (child) => {
|
|
56324
|
-
if (hasUserEdit) return false;
|
|
56325
|
-
if (!isNodeOfType(child, "CallExpression")) return;
|
|
56326
|
-
if (!isReferenceToBinding(child.callee, setterBinding, context)) return;
|
|
56327
|
-
if (!isHandlerShapedReseed(child, componentFunction)) return;
|
|
56328
|
-
const setterArgument = child.arguments?.[0];
|
|
56329
|
-
if (!setterArgument || isPropDerivedArgument(unwrapInitializerSeed(setterArgument), isPropName)) return;
|
|
56330
|
-
hasUserEdit = true;
|
|
56331
|
-
return false;
|
|
56332
|
-
});
|
|
56333
|
-
return hasControlledFallback && hasUserEdit;
|
|
56334
|
-
};
|
|
56335
56293
|
const getStateValueName = (useStateCall) => {
|
|
56336
56294
|
const declarator = useStateCall.parent;
|
|
56337
56295
|
if (!isNodeOfType(declarator, "VariableDeclarator")) return null;
|
|
@@ -56396,7 +56354,6 @@ const noDerivedUseState = defineRule({
|
|
|
56396
56354
|
const reportStalePropCopy = (propName) => {
|
|
56397
56355
|
if (isIntentionalSnapshotState(node)) return;
|
|
56398
56356
|
if (hasSessionDismissProp(propStackTracker.getCurrentPropNames())) return;
|
|
56399
|
-
if (isUserEditableControlledFallback(node, propStackTracker.isPropName, context)) return;
|
|
56400
56357
|
if (isDraftReseedOrRenderAdjusted(node, propStackTracker.isPropName)) return;
|
|
56401
56358
|
if (isEffectDrivenResync(node)) return;
|
|
56402
56359
|
if (isNextjsDataFetchingPage(node)) return;
|
|
@@ -67234,124 +67191,6 @@ const isInsideSnapshotHelper = (node) => {
|
|
|
67234
67191
|
}
|
|
67235
67192
|
return false;
|
|
67236
67193
|
};
|
|
67237
|
-
const findEnclosingNextjsPageDataFunction = (node) => {
|
|
67238
|
-
let outermostFunction = null;
|
|
67239
|
-
let cursor = node.parent;
|
|
67240
|
-
while (cursor) {
|
|
67241
|
-
if (isFunctionLike$1(cursor)) outermostFunction = cursor;
|
|
67242
|
-
if (isNodeOfType(cursor, "Program")) {
|
|
67243
|
-
if (!outermostFunction) return null;
|
|
67244
|
-
for (const exportName of NEXTJS_PAGE_DATA_EXPORT_NAMES) {
|
|
67245
|
-
const exportedValue = findExportedValue(cursor, exportName);
|
|
67246
|
-
if (exportedValue && isAstDescendant(outermostFunction, exportedValue)) return outermostFunction;
|
|
67247
|
-
}
|
|
67248
|
-
return null;
|
|
67249
|
-
}
|
|
67250
|
-
cursor = cursor.parent ?? null;
|
|
67251
|
-
}
|
|
67252
|
-
return null;
|
|
67253
|
-
};
|
|
67254
|
-
const findConditionalReturnExpressionRoot = (node) => {
|
|
67255
|
-
let expressionRoot = findTransparentExpressionRoot(node);
|
|
67256
|
-
while (expressionRoot.parent && isNodeOfType(expressionRoot.parent, "ConditionalExpression") && (expressionRoot.parent.consequent === expressionRoot || expressionRoot.parent.alternate === expressionRoot)) expressionRoot = findTransparentExpressionRoot(expressionRoot.parent);
|
|
67257
|
-
return expressionRoot;
|
|
67258
|
-
};
|
|
67259
|
-
const isReturnedPageDataResultBinding = (returnExpression, pageDataFunction, context) => {
|
|
67260
|
-
const declarator = returnExpression.parent;
|
|
67261
|
-
if (!isNodeOfType(declarator, "VariableDeclarator") || declarator.init !== returnExpression || !isNodeOfType(declarator.id, "Identifier") || findEnclosingFunction$1(declarator) !== pageDataFunction) return false;
|
|
67262
|
-
const bindingSymbol = context.scopes.symbolFor(declarator.id);
|
|
67263
|
-
if (!bindingSymbol || bindingSymbol.references.length !== 1) return false;
|
|
67264
|
-
const referenceRoot = findTransparentExpressionRoot(bindingSymbol.references[0].identifier);
|
|
67265
|
-
const returnStatement = referenceRoot.parent;
|
|
67266
|
-
return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === referenceRoot && findEnclosingFunction$1(returnStatement) === pageDataFunction;
|
|
67267
|
-
};
|
|
67268
|
-
const isSameShorthandPropertyValue = (node, property) => property.shorthand && (node === property.key || node === property.value);
|
|
67269
|
-
const isValueForwardedThroughLiteralStructure = (node, structure) => {
|
|
67270
|
-
const strippedNode = stripParenExpression(node);
|
|
67271
|
-
const strippedStructure = stripParenExpression(structure);
|
|
67272
|
-
if (strippedNode === strippedStructure) return true;
|
|
67273
|
-
if (isNodeOfType(strippedStructure, "ConditionalExpression")) return isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.consequent) || isValueForwardedThroughLiteralStructure(strippedNode, strippedStructure.alternate);
|
|
67274
|
-
if (isNodeOfType(strippedStructure, "ArrayExpression")) return strippedStructure.elements.some((element) => element && !isNodeOfType(element, "SpreadElement") && isValueForwardedThroughLiteralStructure(strippedNode, element));
|
|
67275
|
-
if (!isNodeOfType(strippedStructure, "ObjectExpression")) return false;
|
|
67276
|
-
return strippedStructure.properties.some((property) => {
|
|
67277
|
-
if (isNodeOfType(property, "SpreadElement")) return isValueForwardedThroughLiteralStructure(strippedNode, property.argument);
|
|
67278
|
-
if (!isNodeOfType(property, "Property")) return false;
|
|
67279
|
-
if (isValueForwardedThroughLiteralStructure(strippedNode, property.value)) return true;
|
|
67280
|
-
return isSameShorthandPropertyValue(strippedNode, property);
|
|
67281
|
-
});
|
|
67282
|
-
};
|
|
67283
|
-
const isValueForwardedToPropertyValue = (node, property) => {
|
|
67284
|
-
const directValue = findConditionalReturnExpressionRoot(node);
|
|
67285
|
-
if (isValueForwardedThroughLiteralStructure(directValue, property.value)) return true;
|
|
67286
|
-
return isSameShorthandPropertyValue(directValue, property);
|
|
67287
|
-
};
|
|
67288
|
-
const isInsideReturnedNextjsProps = (node, pageDataFunction, context) => {
|
|
67289
|
-
let cursor = node.parent;
|
|
67290
|
-
while (cursor && cursor !== pageDataFunction) {
|
|
67291
|
-
if (isNodeOfType(cursor, "Property") && getStaticPropertyKeyName(cursor, { allowComputedString: true }) === "props" && isValueForwardedToPropertyValue(node, cursor)) {
|
|
67292
|
-
const propertyContainer = cursor.parent;
|
|
67293
|
-
if (!propertyContainer) return false;
|
|
67294
|
-
const returnExpression = findConditionalReturnExpressionRoot(propertyContainer);
|
|
67295
|
-
const returnStatement = returnExpression.parent;
|
|
67296
|
-
if (isNodeOfType(returnStatement, "ReturnStatement") && findEnclosingFunction$1(returnStatement) === pageDataFunction) return true;
|
|
67297
|
-
if (isNodeOfType(pageDataFunction, "ArrowFunctionExpression") && !isNodeOfType(pageDataFunction.body, "BlockStatement") && stripParenExpression(pageDataFunction.body) === stripParenExpression(returnExpression)) return true;
|
|
67298
|
-
if (isReturnedPageDataResultBinding(returnExpression, pageDataFunction, context)) return true;
|
|
67299
|
-
}
|
|
67300
|
-
cursor = cursor.parent ?? null;
|
|
67301
|
-
}
|
|
67302
|
-
return false;
|
|
67303
|
-
};
|
|
67304
|
-
const isExpressionReturnedByFunction = (node, functionNode) => {
|
|
67305
|
-
const returnExpression = findConditionalReturnExpressionRoot(node);
|
|
67306
|
-
if (isNodeOfType(functionNode, "ArrowFunctionExpression") && !isNodeOfType(functionNode.body, "BlockStatement")) return stripParenExpression(functionNode.body) === stripParenExpression(returnExpression);
|
|
67307
|
-
const returnStatement = returnExpression.parent;
|
|
67308
|
-
return isNodeOfType(returnStatement, "ReturnStatement") && returnStatement.argument === returnExpression && findEnclosingFunction$1(returnStatement) === functionNode;
|
|
67309
|
-
};
|
|
67310
|
-
const isValueForwardedToBindingInitializer = (node, bindingInitializer) => {
|
|
67311
|
-
if (isValueForwardedThroughLiteralStructure(findConditionalReturnExpressionRoot(node), bindingInitializer)) return true;
|
|
67312
|
-
const initializer = stripParenExpression(bindingInitializer);
|
|
67313
|
-
if (!isNodeOfType(initializer, "CallExpression")) return false;
|
|
67314
|
-
const callee = stripParenExpression(initializer.callee);
|
|
67315
|
-
return isFunctionLike$1(callee) && isExpressionReturnedByFunction(node, callee);
|
|
67316
|
-
};
|
|
67317
|
-
const findPageDataResultBinding = (node) => {
|
|
67318
|
-
let cursor = node.parent;
|
|
67319
|
-
while (cursor) {
|
|
67320
|
-
if (isNodeOfType(cursor, "VariableDeclarator")) {
|
|
67321
|
-
if (cursor.init && isNodeOfType(cursor.id, "Identifier") && isValueForwardedToBindingInitializer(node, cursor.init)) return cursor.id;
|
|
67322
|
-
return null;
|
|
67323
|
-
}
|
|
67324
|
-
cursor = cursor.parent ?? null;
|
|
67325
|
-
}
|
|
67326
|
-
return null;
|
|
67327
|
-
};
|
|
67328
|
-
const isUsedToSerializeNextjsPageProps = (node, context) => {
|
|
67329
|
-
if (!isInProjectDirectory(context, "pages") || isInProjectDirectory(context, "pages/api")) return false;
|
|
67330
|
-
const pageDataFunction = findEnclosingNextjsPageDataFunction(node);
|
|
67331
|
-
if (!pageDataFunction) return false;
|
|
67332
|
-
if (isInsideReturnedNextjsProps(node, pageDataFunction, context)) return true;
|
|
67333
|
-
const bindingIdentifier = findPageDataResultBinding(node);
|
|
67334
|
-
const bindingSymbol = bindingIdentifier ? context.scopes.symbolFor(bindingIdentifier) : null;
|
|
67335
|
-
if (!bindingSymbol) return false;
|
|
67336
|
-
const aliasSymbols = collectConstAliasSymbols(bindingSymbol, context.scopes);
|
|
67337
|
-
const aliasSymbolIds = new Set(aliasSymbols.map((aliasSymbol) => aliasSymbol.id));
|
|
67338
|
-
let hasPagePropsReference = false;
|
|
67339
|
-
for (const aliasSymbol of aliasSymbols) for (const reference of aliasSymbol.references) {
|
|
67340
|
-
if (findEnclosingFunction$1(reference.identifier) !== pageDataFunction) return false;
|
|
67341
|
-
if (isInsideReturnedNextjsProps(reference.identifier, pageDataFunction, context)) {
|
|
67342
|
-
hasPagePropsReference = true;
|
|
67343
|
-
continue;
|
|
67344
|
-
}
|
|
67345
|
-
const referenceRoot = findTransparentExpressionRoot(reference.identifier);
|
|
67346
|
-
const declarator = referenceRoot.parent;
|
|
67347
|
-
if (isNodeOfType(declarator, "VariableDeclarator") && declarator.init === referenceRoot && isNodeOfType(declarator.id, "Identifier")) {
|
|
67348
|
-
const aliasSymbolForReference = context.scopes.symbolFor(declarator.id);
|
|
67349
|
-
if (aliasSymbolForReference && aliasSymbolIds.has(aliasSymbolForReference.id)) continue;
|
|
67350
|
-
}
|
|
67351
|
-
return false;
|
|
67352
|
-
}
|
|
67353
|
-
return hasPagePropsReference;
|
|
67354
|
-
};
|
|
67355
67194
|
const noJsonParseStringifyClone = defineRule({
|
|
67356
67195
|
id: "no-json-parse-stringify-clone",
|
|
67357
67196
|
title: "JSON parse/stringify deep clone",
|
|
@@ -67369,7 +67208,6 @@ const noJsonParseStringifyClone = defineRule({
|
|
|
67369
67208
|
if (isInsideSnapshotHelper(node)) return;
|
|
67370
67209
|
if (isAssignedToNormalizationBinding(node)) return;
|
|
67371
67210
|
if (isCatchParameterRoundTrip(firstArgument)) return;
|
|
67372
|
-
if (isUsedToSerializeNextjsPageProps(node, context)) return;
|
|
67373
67211
|
context.report({
|
|
67374
67212
|
node,
|
|
67375
67213
|
message: MESSAGE$35
|
|
@@ -79995,23 +79833,16 @@ const MAX_INITIATOR_RESOLUTION_DEPTH = 3;
|
|
|
79995
79833
|
const STATE_DISPATCHER_HOOK_NAMES = new Set(["useState", "useReducer"]);
|
|
79996
79834
|
const REF_HOOK_NAMES = new Set(["useRef"]);
|
|
79997
79835
|
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).";
|
|
79998
|
-
const
|
|
79836
|
+
const isKnownNonThenableHandlerReturn = (expression, context, visitedBindingIdentifiers = /* @__PURE__ */ new Set()) => {
|
|
79999
79837
|
const strippedExpression = stripParenExpression(expression);
|
|
80000
79838
|
if (isDefinitelyNonThenableValue(strippedExpression)) return true;
|
|
80001
|
-
if (isNodeOfType(strippedExpression, "CallExpression") && isNodeOfType(strippedExpression.callee, "MemberExpression")) {
|
|
80002
|
-
const receiver = stripParenExpression(strippedExpression.callee.object);
|
|
80003
|
-
if (isNodeOfType(receiver, "Identifier") && receiver.name === "Promise" && context.scopes.isGlobalReference(receiver) && getStaticPropertyName(strippedExpression.callee) === "resolve") {
|
|
80004
|
-
const resolvedValue = strippedExpression.arguments[0];
|
|
80005
|
-
return !resolvedValue || !isNodeOfType(resolvedValue, "SpreadElement") && isKnownNonRejectingHandlerReturn(resolvedValue, context, visitedBindingIdentifiers);
|
|
80006
|
-
}
|
|
80007
|
-
}
|
|
80008
79839
|
if (!isNodeOfType(strippedExpression, "Identifier")) return false;
|
|
80009
79840
|
if (strippedExpression.name === "undefined" && context.scopes.isGlobalReference(strippedExpression)) return true;
|
|
80010
79841
|
const symbol = context.scopes.symbolFor(strippedExpression);
|
|
80011
79842
|
if (!symbol || visitedBindingIdentifiers.has(symbol.bindingIdentifier)) return false;
|
|
80012
79843
|
visitedBindingIdentifiers.add(symbol.bindingIdentifier);
|
|
80013
79844
|
const initializer = getDirectUnreassignedInitializer(symbol);
|
|
80014
|
-
return Boolean(initializer &&
|
|
79845
|
+
return Boolean(initializer && isKnownNonThenableHandlerReturn(initializer, context, visitedBindingIdentifiers));
|
|
80015
79846
|
};
|
|
80016
79847
|
const isKnownNonRejectingHandler = (argument, context) => {
|
|
80017
79848
|
if (!argument) return false;
|
|
@@ -80026,7 +79857,7 @@ const isKnownNonRejectingHandler = (argument, context) => {
|
|
|
80026
79857
|
canReject = true;
|
|
80027
79858
|
return false;
|
|
80028
79859
|
}
|
|
80029
|
-
if (isNodeOfType(child, "ReturnStatement") && child.argument && !
|
|
79860
|
+
if (isNodeOfType(child, "ReturnStatement") && child.argument && !isKnownNonThenableHandlerReturn(child.argument, context)) {
|
|
80030
79861
|
if (!isNodeOfType(stripParenExpression(child.argument), "CallExpression")) {
|
|
80031
79862
|
canReject = true;
|
|
80032
79863
|
return false;
|
|
@@ -80075,28 +79906,6 @@ const handlerHasPotentiallyThrowingMemberRead = (argument, context) => {
|
|
|
80075
79906
|
});
|
|
80076
79907
|
return hasPotentiallyThrowingMemberRead;
|
|
80077
79908
|
};
|
|
80078
|
-
const hasRejectionHandler = (chain, argument, context, allowTerminalCatchBlock) => {
|
|
80079
|
-
if (!argument) return false;
|
|
80080
|
-
if (!handlerHasPotentiallyThrowingMemberRead(argument, context) && (chainCarriesRejectionHandler(chain, context.scopes) || isKnownNonRejectingHandler(argument, context))) return true;
|
|
80081
|
-
if (!allowTerminalCatchBlock) return false;
|
|
80082
|
-
const candidate = stripParenExpression(argument);
|
|
80083
|
-
const handler = isNodeOfType(candidate, "Identifier") ? resolveExactLocalFunction(candidate, context.scopes) : candidate;
|
|
80084
|
-
if (!handler || !isFunctionLike$1(handler)) return isNodeOfType(candidate, "MemberExpression") || isNodeOfType(candidate, "Identifier") && candidate.name !== "undefined";
|
|
80085
|
-
if (!isNodeOfType(handler.body, "BlockStatement")) return false;
|
|
80086
|
-
let doesExplicitlyReject = false;
|
|
80087
|
-
walkOwnFunctionScope(handler, (child) => {
|
|
80088
|
-
if (doesExplicitlyReject) return false;
|
|
80089
|
-
if (isNodeOfType(child, "ThrowStatement") || isNodeOfType(child, "AwaitExpression")) {
|
|
80090
|
-
doesExplicitlyReject = true;
|
|
80091
|
-
return false;
|
|
80092
|
-
}
|
|
80093
|
-
if (isNodeOfType(child, "ReturnStatement") && child.argument && !isKnownNonRejectingHandlerReturn(child.argument, context)) {
|
|
80094
|
-
doesExplicitlyReject = true;
|
|
80095
|
-
return false;
|
|
80096
|
-
}
|
|
80097
|
-
});
|
|
80098
|
-
return !doesExplicitlyReject;
|
|
80099
|
-
};
|
|
80100
79909
|
const walkPromiseChain = (chainExpression, context) => {
|
|
80101
79910
|
let cursor = stripParenExpression(chainExpression);
|
|
80102
79911
|
let hasCatch = false;
|
|
@@ -80108,9 +79917,10 @@ const walkPromiseChain = (chainExpression, context) => {
|
|
|
80108
79917
|
while (isNodeOfType(cursor, "CallExpression") && isNodeOfType(cursor.callee, "MemberExpression") && PROMISE_METHOD_NAMES.has(getStaticPropertyName(cursor.callee) ?? "")) {
|
|
80109
79918
|
const methodName = getStaticPropertyName(cursor.callee);
|
|
80110
79919
|
const rejectionHandlerArgument = methodName === "catch" ? cursor.arguments[0] : cursor.arguments[1];
|
|
80111
|
-
|
|
79920
|
+
const hasAbsorbingRejectionHandler = !handlerHasPotentiallyThrowingMemberRead(rejectionHandlerArgument, context) && (chainCarriesRejectionHandler(cursor, context.scopes) || isKnownNonRejectingHandler(rejectionHandlerArgument, context));
|
|
79921
|
+
if (!didReachTerminalThen && methodName === "catch" && hasAbsorbingRejectionHandler) hasCatch = true;
|
|
80112
79922
|
if (methodName === "then") {
|
|
80113
|
-
if (!didReachTerminalThen &&
|
|
79923
|
+
if (!didReachTerminalThen && hasAbsorbingRejectionHandler) hasRejectionHandlerArgument = true;
|
|
80114
79924
|
didReachTerminalThen = true;
|
|
80115
79925
|
sawThen = true;
|
|
80116
79926
|
const callbackArgument = cursor.arguments[0];
|
|
@@ -82437,45 +82247,6 @@ const noRefCallbackCleanupBeforeReact19 = defineRule({
|
|
|
82437
82247
|
} })
|
|
82438
82248
|
});
|
|
82439
82249
|
//#endregion
|
|
82440
|
-
//#region src/plugin/utils/contains-non-deterministic-source.ts
|
|
82441
|
-
const NON_DETERMINISTIC_MEMBER_CALLS = new Set([
|
|
82442
|
-
"Math.random",
|
|
82443
|
-
"Date.now",
|
|
82444
|
-
"performance.now",
|
|
82445
|
-
"crypto.randomUUID",
|
|
82446
|
-
"crypto.getRandomValues"
|
|
82447
|
-
]);
|
|
82448
|
-
const NON_DETERMINISTIC_ID_GENERATOR_NAMES = new Set([
|
|
82449
|
-
"nanoid",
|
|
82450
|
-
"uuid",
|
|
82451
|
-
"cuid",
|
|
82452
|
-
"ulid",
|
|
82453
|
-
"createId"
|
|
82454
|
-
]);
|
|
82455
|
-
const isZeroArgDateConstruction = (node) => isNodeOfType(node, "NewExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "Date" && (node.arguments?.length ?? 0) === 0;
|
|
82456
|
-
const containsNonDeterministicSource = (root) => {
|
|
82457
|
-
let found = false;
|
|
82458
|
-
walkAst(root, (child) => {
|
|
82459
|
-
if (found) return false;
|
|
82460
|
-
if (isFunctionLike$1(child)) return false;
|
|
82461
|
-
if (isZeroArgDateConstruction(child)) {
|
|
82462
|
-
found = true;
|
|
82463
|
-
return false;
|
|
82464
|
-
}
|
|
82465
|
-
if (!isNodeOfType(child, "CallExpression")) return;
|
|
82466
|
-
const callee = child.callee;
|
|
82467
|
-
if (isNodeOfType(callee, "Identifier") && NON_DETERMINISTIC_ID_GENERATOR_NAMES.has(callee.name)) {
|
|
82468
|
-
found = true;
|
|
82469
|
-
return false;
|
|
82470
|
-
}
|
|
82471
|
-
if (isNodeOfType(callee, "MemberExpression") && isNodeOfType(callee.object, "Identifier") && isNodeOfType(callee.property, "Identifier") && NON_DETERMINISTIC_MEMBER_CALLS.has(`${callee.object.name}.${callee.property.name}`)) {
|
|
82472
|
-
found = true;
|
|
82473
|
-
return false;
|
|
82474
|
-
}
|
|
82475
|
-
});
|
|
82476
|
-
return found;
|
|
82477
|
-
};
|
|
82478
|
-
//#endregion
|
|
82479
82250
|
//#region src/plugin/rules/state-and-effects/no-ref-current-in-render.ts
|
|
82480
82251
|
const REPEATED_ANCESTOR_TYPES = new Set([
|
|
82481
82252
|
"DoWhileStatement",
|
|
@@ -82506,75 +82277,45 @@ const resolveImmutableInitializationValue = (node, scopes, visitedSymbolIds = /*
|
|
|
82506
82277
|
};
|
|
82507
82278
|
const isProvablyTruthyInitializationValue = (node, scopes) => {
|
|
82508
82279
|
const expression = resolveImmutableInitializationValue(node, scopes);
|
|
82509
|
-
|
|
82510
|
-
if (isNodeOfType(expression, "CallExpression")) {
|
|
82511
|
-
const callee = stripParenExpression(expression.callee);
|
|
82512
|
-
return isNodeOfType(callee, "Identifier") && callee.name.startsWith("create");
|
|
82513
|
-
}
|
|
82514
|
-
return isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression");
|
|
82280
|
+
return Boolean(expression && (isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression")));
|
|
82515
82281
|
};
|
|
82516
|
-
const
|
|
82282
|
+
const getInitializationConstructorName = (node, scopes) => {
|
|
82517
82283
|
const expression = resolveImmutableInitializationValue(node, scopes);
|
|
82518
82284
|
if (!expression) return null;
|
|
82519
|
-
if (isNodeOfType(expression, "NewExpression")
|
|
82285
|
+
if (isNodeOfType(expression, "NewExpression")) {
|
|
82520
82286
|
const callee = stripParenExpression(expression.callee);
|
|
82521
|
-
|
|
82522
|
-
return callee.name.startsWith("create") && callee.name.length > 6 ? callee.name.slice(6) : callee.name;
|
|
82287
|
+
return isNodeOfType(callee, "Identifier") ? callee.name : null;
|
|
82523
82288
|
}
|
|
82524
82289
|
return null;
|
|
82525
82290
|
};
|
|
82526
|
-
const isMatchingReturnType = (typeNode, initializationValue, scopes) => {
|
|
82527
|
-
if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
|
|
82528
|
-
const typeName = typeNode.typeName;
|
|
82529
|
-
if (!isNodeOfType(typeName, "Identifier") || typeName.name !== "ReturnType") return false;
|
|
82530
|
-
const [returnTypeArgument] = typeNode.typeArguments?.params ?? [];
|
|
82531
|
-
if (!returnTypeArgument || !isNodeOfType(returnTypeArgument, "TSTypeQuery")) return false;
|
|
82532
|
-
const queriedName = returnTypeArgument.exprName;
|
|
82533
|
-
const expression = stripParenExpression(initializationValue);
|
|
82534
|
-
if (!isNodeOfType(queriedName, "Identifier") || !isNodeOfType(expression, "CallExpression")) return false;
|
|
82535
|
-
const callee = stripParenExpression(expression.callee);
|
|
82536
|
-
if (!isNodeOfType(callee, "Identifier")) return false;
|
|
82537
|
-
const queriedSymbol = scopes.symbolFor(queriedName);
|
|
82538
|
-
const calleeSymbol = scopes.symbolFor(callee);
|
|
82539
|
-
return queriedSymbol && calleeSymbol ? queriedSymbol.id === calleeSymbol.id : queriedName.name === callee.name;
|
|
82540
|
-
};
|
|
82541
82291
|
const isClosedTruthyTypeDomain = (typeNode, initializationValue, scopes) => {
|
|
82542
82292
|
const initializationExpression = stripParenExpression(initializationValue);
|
|
82543
82293
|
if (isNodeOfType(typeNode, "TSTypeLiteral")) return isNodeOfType(initializationExpression, "ObjectExpression");
|
|
82544
82294
|
if (isNodeOfType(typeNode, "TSArrayType") || isNodeOfType(typeNode, "TSTupleType")) return isNodeOfType(initializationExpression, "ArrayExpression");
|
|
82545
82295
|
if (isNodeOfType(typeNode, "TSFunctionType") || isNodeOfType(typeNode, "TSConstructorType")) return isNodeOfType(initializationExpression, "ArrowFunctionExpression") || isNodeOfType(initializationExpression, "FunctionExpression") || isNodeOfType(initializationExpression, "ClassExpression");
|
|
82546
82296
|
if (isNodeOfType(typeNode, "TSObjectKeyword")) return true;
|
|
82547
|
-
if (isNodeOfType(typeNode, "TSIndexedAccessType")) return isNodeOfType(initializationExpression, "ObjectExpression");
|
|
82548
82297
|
if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
|
|
82549
82298
|
const typeName = typeNode.typeName;
|
|
82550
|
-
|
|
82551
|
-
return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationValueName(initializationExpression, scopes);
|
|
82299
|
+
return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationConstructorName(initializationExpression, scopes);
|
|
82552
82300
|
};
|
|
82553
82301
|
const refHasClosedFalsySentinelDomain = (refSymbol, initializationValue, scopes) => {
|
|
82554
82302
|
const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
|
|
82555
82303
|
if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
|
|
82556
82304
|
const [initialValue] = initializer.arguments ?? [];
|
|
82557
|
-
if (initialValue
|
|
82305
|
+
if (!initialValue || isNodeOfType(initialValue, "SpreadElement") || !isEmptySentinel(initialValue, scopes)) return false;
|
|
82558
82306
|
const [declaredType] = initializer.typeArguments?.params ?? [];
|
|
82559
|
-
if (!declaredType) return false;
|
|
82560
|
-
|
|
82307
|
+
if (!declaredType || !isNodeOfType(declaredType, "TSUnionType")) return false;
|
|
82308
|
+
let hasEmptySentinel = false;
|
|
82561
82309
|
let hasTruthyDomain = false;
|
|
82562
|
-
for (const memberType of
|
|
82563
|
-
if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword"))
|
|
82310
|
+
for (const memberType of declaredType.types ?? []) {
|
|
82311
|
+
if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword")) {
|
|
82312
|
+
hasEmptySentinel = true;
|
|
82313
|
+
continue;
|
|
82314
|
+
}
|
|
82564
82315
|
if (!isClosedTruthyTypeDomain(memberType, initializationValue, scopes)) return false;
|
|
82565
82316
|
hasTruthyDomain = true;
|
|
82566
82317
|
}
|
|
82567
|
-
return hasTruthyDomain;
|
|
82568
|
-
};
|
|
82569
|
-
const refHasEmptySentinelInitializer = (refSymbol, scopes) => {
|
|
82570
|
-
const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
|
|
82571
|
-
if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
|
|
82572
|
-
const [initialValue] = initializer.arguments ?? [];
|
|
82573
|
-
return Boolean(!initialValue || !isNodeOfType(initialValue, "SpreadElement") && isEmptySentinel(initialValue, scopes));
|
|
82574
|
-
};
|
|
82575
|
-
const refHasDeclaredType = (refSymbol) => {
|
|
82576
|
-
const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
|
|
82577
|
-
return Boolean(initializer && isNodeOfType(initializer, "CallExpression") && (initializer.typeArguments?.params.length ?? 0) > 0);
|
|
82318
|
+
return hasEmptySentinel && hasTruthyDomain;
|
|
82578
82319
|
};
|
|
82579
82320
|
const isSafeRefIdentifierUse = (identifier) => {
|
|
82580
82321
|
const expressionRoot = findTransparentExpressionRoot(identifier);
|
|
@@ -82606,40 +82347,25 @@ const expressionContainsRefCurrent = (expression, refSymbol, scopes) => {
|
|
|
82606
82347
|
});
|
|
82607
82348
|
return didFindRefCurrent;
|
|
82608
82349
|
};
|
|
82609
|
-
const
|
|
82610
|
-
|
|
82611
|
-
|
|
82612
|
-
|
|
82613
|
-
|
|
82614
|
-
|
|
82615
|
-
|
|
82616
|
-
if (!isInputIndependent) return false;
|
|
82617
|
-
if (resolveReactRefSymbol(child, scopes)) return false;
|
|
82618
|
-
if (!isNodeOfType(child, "Identifier")) return;
|
|
82619
|
-
const symbol = scopes.symbolFor(child);
|
|
82620
|
-
if (!symbol) return;
|
|
82621
|
-
if (symbol.kind === "import") return false;
|
|
82622
|
-
if (symbol.kind === "let" || symbol.kind === "var" || symbol.kind === "using") {
|
|
82623
|
-
isInputIndependent = false;
|
|
82624
|
-
return false;
|
|
82350
|
+
const hasNoCompetingRefCurrentWrite = (branchRoot, assignmentExpression, refSymbol, scopes) => {
|
|
82351
|
+
let writeCount = 0;
|
|
82352
|
+
walkAst(branchRoot, (child) => {
|
|
82353
|
+
if (writeCount > 1) return false;
|
|
82354
|
+
if (isNodeOfType(child, "AssignmentExpression")) {
|
|
82355
|
+
if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
|
|
82356
|
+
return;
|
|
82625
82357
|
}
|
|
82626
|
-
if (
|
|
82627
|
-
|
|
82628
|
-
|
|
82629
|
-
return false;
|
|
82358
|
+
if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") {
|
|
82359
|
+
if (expressionContainsRefCurrent(child.argument, refSymbol, scopes)) writeCount++;
|
|
82360
|
+
return;
|
|
82630
82361
|
}
|
|
82631
|
-
if (
|
|
82632
|
-
|
|
82633
|
-
return false;
|
|
82362
|
+
if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) {
|
|
82363
|
+
if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
|
|
82634
82364
|
}
|
|
82635
|
-
if (visitedSymbolIds.has(symbol.id)) return false;
|
|
82636
|
-
visitedSymbolIds.add(symbol.id);
|
|
82637
|
-
if (!isInitializationInputIndependent(symbol.initializer, renderOwner, scopes, visitedSymbolIds)) isInputIndependent = false;
|
|
82638
|
-
return false;
|
|
82639
82365
|
});
|
|
82640
|
-
return
|
|
82366
|
+
return writeCount === 1 && expressionContainsRefCurrent(assignmentExpression.left, refSymbol, scopes);
|
|
82641
82367
|
};
|
|
82642
|
-
const
|
|
82368
|
+
const isEmptySentinel = (node, scopes) => isNodeOfType(node, "Literal") && node.value === null || isNodeOfType(node, "Identifier") && node.name === "undefined" && scopes.isGlobalReference(node);
|
|
82643
82369
|
const hasRepeatedExecutionAncestor = (node, stop) => {
|
|
82644
82370
|
let ancestor = node.parent;
|
|
82645
82371
|
while (ancestor && ancestor !== stop) {
|
|
@@ -82669,27 +82395,6 @@ const canExecuteTogether = (firstConstraints, secondConstraints) => {
|
|
|
82669
82395
|
}
|
|
82670
82396
|
return true;
|
|
82671
82397
|
};
|
|
82672
|
-
const hasNoCoExecutableCompetingWrite = (assignmentExpression, renderOwner, refSymbol, scopes) => {
|
|
82673
|
-
const assignmentConstraints = getBranchConstraints(assignmentExpression, renderOwner);
|
|
82674
|
-
const synchronouslyInvokedFunctions = collectSynchronouslyEffectInvokedFunctions(renderOwner, scopes);
|
|
82675
|
-
let hasCompetingWrite = false;
|
|
82676
|
-
walkAst(renderOwner, (child) => {
|
|
82677
|
-
if (hasCompetingWrite) return false;
|
|
82678
|
-
let writtenExpression = null;
|
|
82679
|
-
if (isNodeOfType(child, "AssignmentExpression")) {
|
|
82680
|
-
if (child === assignmentExpression) return;
|
|
82681
|
-
writtenExpression = child.left;
|
|
82682
|
-
} else if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") writtenExpression = child.argument;
|
|
82683
|
-
else if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) writtenExpression = child.left;
|
|
82684
|
-
const deferredExecutionBoundary = findDeferredExecutionBoundary(child);
|
|
82685
|
-
const deferredWriteValue = isNodeOfType(child, "AssignmentExpression") && child.operator === "=" ? resolveImmutableInitializationValue(child.right, scopes) : null;
|
|
82686
|
-
const isDeferredTruthyWrite = deferredExecutionBoundary !== null && deferredExecutionBoundary !== renderOwner && !synchronouslyInvokedFunctions.has(deferredExecutionBoundary) && !executesDuringRender(deferredExecutionBoundary, scopes) && deferredWriteValue !== null && !isNodeOfType(deferredWriteValue, "CallExpression") && isProvablyTruthyInitializationValue(deferredWriteValue, scopes);
|
|
82687
|
-
if (!writtenExpression || isDeferredTruthyWrite || !expressionContainsRefCurrent(writtenExpression, refSymbol, scopes) || !canExecuteTogether(assignmentConstraints, getBranchConstraints(child, renderOwner))) return;
|
|
82688
|
-
hasCompetingWrite = true;
|
|
82689
|
-
return false;
|
|
82690
|
-
});
|
|
82691
|
-
return !hasCompetingWrite;
|
|
82692
|
-
};
|
|
82693
82398
|
const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol, scopes) => {
|
|
82694
82399
|
const assignmentConstraints = getBranchConstraints(assignmentExpression, branchRoot);
|
|
82695
82400
|
const assignmentStart = getRangeStart(assignmentExpression);
|
|
@@ -82705,17 +82410,16 @@ const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol
|
|
|
82705
82410
|
});
|
|
82706
82411
|
return !hasCoExecutableWrite;
|
|
82707
82412
|
};
|
|
82708
|
-
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);
|
|
82709
82413
|
const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes) => {
|
|
82414
|
+
if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return true;
|
|
82415
|
+
if (assignmentExpression.operator !== "=") return false;
|
|
82710
82416
|
const renderOwner = findRenderPhaseComponentOrHook(assignmentExpression, scopes);
|
|
82711
82417
|
if (!renderOwner) return false;
|
|
82712
|
-
if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return isPredictableGuardedInitialization(assignmentExpression, renderOwner, renderOwner, refSymbol, scopes, assignmentExpression.operator === "||=");
|
|
82713
|
-
if (assignmentExpression.operator !== "=") return false;
|
|
82714
82418
|
let descendant = assignmentExpression;
|
|
82715
82419
|
let ancestor = descendant.parent;
|
|
82716
82420
|
while (ancestor) {
|
|
82717
82421
|
const test = isNodeOfType(ancestor, "IfStatement") ? stripParenExpression(ancestor.test) : null;
|
|
82718
|
-
if (isNodeOfType(ancestor, "IfStatement") && test && isNodeOfType(test, "UnaryExpression") && test.operator === "!" && isSameRefCurrentAlias(test.argument, refSymbol, scopes) && ancestor.consequent === descendant &&
|
|
82422
|
+
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;
|
|
82719
82423
|
if (isNodeOfType(ancestor, "IfStatement") && isNodeOfType(test, "BinaryExpression") && [
|
|
82720
82424
|
"===",
|
|
82721
82425
|
"==",
|
|
@@ -82725,7 +82429,7 @@ const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes)
|
|
|
82725
82429
|
const { left, right } = test;
|
|
82726
82430
|
const comparesEmptySentinel = isSameRefCurrentAlias(left, refSymbol, scopes) && isEmptySentinel(right, scopes) || isSameRefCurrentAlias(right, refSymbol, scopes) && isEmptySentinel(left, scopes);
|
|
82727
82431
|
const guardedBranch = test.operator === "===" || test.operator === "==" ? ancestor.consequent : ancestor.alternate;
|
|
82728
|
-
if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch &&
|
|
82432
|
+
if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch && !hasRepeatedExecutionAncestor(assignmentExpression, guardedBranch) && hasNoPriorCoExecutableWrite(assignmentExpression, guardedBranch, refSymbol, scopes)) return true;
|
|
82729
82433
|
}
|
|
82730
82434
|
descendant = ancestor;
|
|
82731
82435
|
ancestor = descendant.parent;
|