oxlint-plugin-react-doctor 0.7.4-dev.5aa82e8 → 0.7.4-dev.63fc41f
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 +20 -202
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -553,7 +553,7 @@ const EXTERNAL_SYNC_OBSERVER_CONSTRUCTORS = new Set([
|
|
|
553
553
|
"ResizeObserver",
|
|
554
554
|
"PerformanceObserver"
|
|
555
555
|
]);
|
|
556
|
-
const STORAGE_OBJECTS = new Set(["localStorage", "sessionStorage"]);
|
|
556
|
+
const STORAGE_OBJECTS$1 = new Set(["localStorage", "sessionStorage"]);
|
|
557
557
|
//#endregion
|
|
558
558
|
//#region src/plugin/constants/react.ts
|
|
559
559
|
const INDEX_PARAMETER_NAMES = new Set([
|
|
@@ -5139,10 +5139,8 @@ const STORAGE_GLOBALS = new Set([
|
|
|
5139
5139
|
const SENSITIVE_KEY_PATTERN = /token|jwt|secret|password|passwd|credential|api[-_]?key|bearer|private[-_]?key/i;
|
|
5140
5140
|
const NON_AUTH_TOKEN_PATTERN = /csrf|xsrf|device|fcm|apns|push|design|tokeniz|syntax|css|theme|color/i;
|
|
5141
5141
|
const STRONG_AUTH_KEY_PATTERN = /jwt|secret|password|passwd|credential|private[-_]?key|api[-_]?key|bearer|access[-_]?token|refresh[-_]?token|auth[-_]?token|id[-_]?token|session/i;
|
|
5142
|
-
const PRODUCT_API_KEY_COLLECTION_PATTERN = /[._:-](?:created|generated|saved)[-_]?api[-_]?keys$/i;
|
|
5143
5142
|
const isAuthCredentialKey = (key) => {
|
|
5144
5143
|
if (!SENSITIVE_KEY_PATTERN.test(key)) return false;
|
|
5145
|
-
if (PRODUCT_API_KEY_COLLECTION_PATTERN.test(key)) return false;
|
|
5146
5144
|
if (NON_AUTH_TOKEN_PATTERN.test(key) && !STRONG_AUTH_KEY_PATTERN.test(key)) return false;
|
|
5147
5145
|
return true;
|
|
5148
5146
|
};
|
|
@@ -6137,6 +6135,7 @@ const isGlobalMethodCall = (node, objectName, methodName) => {
|
|
|
6137
6135
|
//#region src/plugin/rules/client/client-localstorage-no-version.ts
|
|
6138
6136
|
const VERSIONED_KEY_PATTERN = /(?:[._:-]v\d+|@\d+|\bv\d+\b)/i;
|
|
6139
6137
|
const CAMEL_CASE_VERSIONED_KEY_PATTERN = /[a-z]V\d+/;
|
|
6138
|
+
const STORAGE_OBJECTS = new Set(["localStorage", "sessionStorage"]);
|
|
6140
6139
|
const isVersionedKey = (key) => VERSIONED_KEY_PATTERN.test(key) || CAMEL_CASE_VERSIONED_KEY_PATTERN.test(key);
|
|
6141
6140
|
const isJsonStringifyCall = (node) => isGlobalMethodCall(node, "JSON", "stringify");
|
|
6142
6141
|
const resolveStringKey = (keyArg, context) => {
|
|
@@ -6159,7 +6158,7 @@ const clientLocalstorageNoVersion = defineRule({
|
|
|
6159
6158
|
if (!isNodeOfType(node.callee, "MemberExpression")) return;
|
|
6160
6159
|
const receiver = stripParenExpression(node.callee.object);
|
|
6161
6160
|
if (!isNodeOfType(receiver, "Identifier")) return;
|
|
6162
|
-
if (receiver.name
|
|
6161
|
+
if (!STORAGE_OBJECTS.has(receiver.name)) return;
|
|
6163
6162
|
if (!isNodeOfType(node.callee.property, "Identifier")) return;
|
|
6164
6163
|
if (node.callee.property.name !== "setItem") return;
|
|
6165
6164
|
const keyArg = node.arguments?.[0];
|
|
@@ -8939,7 +8938,7 @@ const getListenerAbortControllerKey = (usage, context) => {
|
|
|
8939
8938
|
}
|
|
8940
8939
|
return null;
|
|
8941
8940
|
};
|
|
8942
|
-
const SYNCHRONOUS_ITERATOR_METHOD_NAMES$
|
|
8941
|
+
const SYNCHRONOUS_ITERATOR_METHOD_NAMES$1 = new Set([
|
|
8943
8942
|
"every",
|
|
8944
8943
|
"filter",
|
|
8945
8944
|
"flatMap",
|
|
@@ -8955,7 +8954,7 @@ const isSynchronousIteratorCallback = (functionNode) => {
|
|
|
8955
8954
|
const callee = stripParenExpression(callNode.callee);
|
|
8956
8955
|
if (!isNodeOfType(callee, "MemberExpression") || callee.computed || !isNodeOfType(callee.property, "Identifier")) return false;
|
|
8957
8956
|
if (isNodeOfType(callee.object, "Identifier") && callee.object.name === "Array" && callee.property.name === "from") return callNode.arguments?.[1] === functionNode;
|
|
8958
|
-
return SYNCHRONOUS_ITERATOR_METHOD_NAMES$
|
|
8957
|
+
return SYNCHRONOUS_ITERATOR_METHOD_NAMES$1.has(callee.property.name) && callNode.arguments?.[0] === functionNode;
|
|
8959
8958
|
};
|
|
8960
8959
|
const findDirectCallForReference = (identifier) => {
|
|
8961
8960
|
const expressionRoot = findTransparentExpressionRoot(identifier);
|
|
@@ -10590,19 +10589,6 @@ const isUnstableInitializer = (node) => {
|
|
|
10590
10589
|
if (isNodeOfType(stripped, "LogicalExpression")) return isUnstableInitializer(stripped.left) || isUnstableInitializer(stripped.right);
|
|
10591
10590
|
return isNodeOfType(stripped, "ObjectExpression") || isNodeOfType(stripped, "ArrayExpression") || isNodeOfType(stripped, "ClassExpression") || isNodeOfType(stripped, "ClassDeclaration") || isNodeOfType(stripped, "JSXElement") || isNodeOfType(stripped, "JSXFragment") || isNodeOfType(stripped, "AssignmentExpression") || isNodeOfType(stripped, "NewExpression");
|
|
10592
10591
|
};
|
|
10593
|
-
const isPotentiallyFreshComparedValue = (node, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
10594
|
-
const candidate = unwrapExpression$3(node);
|
|
10595
|
-
if (isUnstableInitializer(candidate)) return true;
|
|
10596
|
-
if (isNodeOfType(candidate, "ConditionalExpression")) return isPotentiallyFreshComparedValue(candidate.consequent, scopes, visitedSymbolIds) || isPotentiallyFreshComparedValue(candidate.alternate, scopes, visitedSymbolIds);
|
|
10597
|
-
if (isNodeOfType(candidate, "LogicalExpression")) return isPotentiallyFreshComparedValue(candidate.left, scopes, visitedSymbolIds) || isPotentiallyFreshComparedValue(candidate.right, scopes, visitedSymbolIds);
|
|
10598
|
-
if (!isNodeOfType(candidate, "Identifier")) return false;
|
|
10599
|
-
const symbol = scopes.symbolFor(candidate);
|
|
10600
|
-
if (!symbol || visitedSymbolIds.has(symbol.id)) return false;
|
|
10601
|
-
if (symbol.kind === "let" || symbol.kind === "var") return true;
|
|
10602
|
-
if (symbol.kind !== "const" || !symbol.initializer) return false;
|
|
10603
|
-
visitedSymbolIds.add(symbol.id);
|
|
10604
|
-
return isPotentiallyFreshComparedValue(symbol.initializer, scopes, visitedSymbolIds);
|
|
10605
|
-
};
|
|
10606
10592
|
const isExtraDepAllowedForHook = (hookName, node, scopes) => {
|
|
10607
10593
|
if (!isExtraReactiveDepAllowed(node, scopes)) return false;
|
|
10608
10594
|
if (EFFECT_HOOKS_ALLOWING_EXTRA_REACTIVE_DEPS.has(hookName)) return true;
|
|
@@ -10616,52 +10602,6 @@ const isStableSetterLikeSymbol = (symbol, scopes) => {
|
|
|
10616
10602
|
if (!symbolHasStableHookOrigin(symbol, scopes)) return false;
|
|
10617
10603
|
return symbol.name.startsWith("set") || symbol.name.startsWith("dispatch") || symbol.name.startsWith("startTransition");
|
|
10618
10604
|
};
|
|
10619
|
-
const isConvergingFunctionalUpdater = (node, scopes) => {
|
|
10620
|
-
const updater = unwrapExpression$3(node);
|
|
10621
|
-
if (!isNodeOfType(updater, "ArrowFunctionExpression") && !isNodeOfType(updater, "FunctionExpression")) return false;
|
|
10622
|
-
const previousValueParameter = updater.params?.[0];
|
|
10623
|
-
if (!previousValueParameter || !isNodeOfType(previousValueParameter, "Identifier")) return false;
|
|
10624
|
-
let returnedExpression = updater.body;
|
|
10625
|
-
if (isNodeOfType(updater.body, "BlockStatement")) {
|
|
10626
|
-
returnedExpression = null;
|
|
10627
|
-
for (const statement of updater.body.body ?? []) if (isNodeOfType(statement, "ReturnStatement") && statement.argument) {
|
|
10628
|
-
returnedExpression = statement.argument;
|
|
10629
|
-
break;
|
|
10630
|
-
}
|
|
10631
|
-
}
|
|
10632
|
-
const conditional = returnedExpression ? unwrapExpression$3(returnedExpression) : null;
|
|
10633
|
-
if (!conditional || !isNodeOfType(conditional, "ConditionalExpression")) return false;
|
|
10634
|
-
const test = unwrapExpression$3(conditional.test);
|
|
10635
|
-
if (!isNodeOfType(test, "BinaryExpression") || ![
|
|
10636
|
-
"===",
|
|
10637
|
-
"!==",
|
|
10638
|
-
"==",
|
|
10639
|
-
"!="
|
|
10640
|
-
].includes(test.operator)) return false;
|
|
10641
|
-
const isPreviousValue = (expression) => {
|
|
10642
|
-
const candidate = unwrapExpression$3(expression);
|
|
10643
|
-
return isNodeOfType(candidate, "Identifier") && candidate.name === previousValueParameter.name;
|
|
10644
|
-
};
|
|
10645
|
-
let comparedValue = null;
|
|
10646
|
-
if (isPreviousValue(test.left)) comparedValue = test.right;
|
|
10647
|
-
else if (isPreviousValue(test.right)) comparedValue = test.left;
|
|
10648
|
-
if (!comparedValue) return false;
|
|
10649
|
-
if (isPotentiallyFreshComparedValue(comparedValue, scopes)) return false;
|
|
10650
|
-
const isSameComparedValue = (expression) => {
|
|
10651
|
-
const candidate = unwrapExpression$3(expression);
|
|
10652
|
-
const compared = unwrapExpression$3(comparedValue);
|
|
10653
|
-
if (isNodeOfType(candidate, "Identifier") && isNodeOfType(compared, "Identifier")) return candidate.name === compared.name;
|
|
10654
|
-
if (isNodeOfType(candidate, "Literal") && isNodeOfType(compared, "Literal")) return candidate.value === compared.value;
|
|
10655
|
-
return false;
|
|
10656
|
-
};
|
|
10657
|
-
return test.operator === "===" || test.operator === "==" ? isPreviousValue(conditional.consequent) && isSameComparedValue(conditional.alternate) : isSameComparedValue(conditional.consequent) && isPreviousValue(conditional.alternate);
|
|
10658
|
-
};
|
|
10659
|
-
const isGuardedStableSetterCall = (identifier, symbol, scopes) => {
|
|
10660
|
-
const parent = identifier.parent;
|
|
10661
|
-
if (!parent || !isNodeOfType(parent, "CallExpression") || parent.callee !== identifier || !isStableSetterLikeSymbol(symbol, scopes)) return false;
|
|
10662
|
-
const writtenValue = parent.arguments?.[0];
|
|
10663
|
-
return Boolean(writtenValue && isConvergingFunctionalUpdater(writtenValue, scopes));
|
|
10664
|
-
};
|
|
10665
10605
|
const findStableSetterReference = (node, scopes) => {
|
|
10666
10606
|
let setterName = null;
|
|
10667
10607
|
const visit = (current) => {
|
|
@@ -10669,7 +10609,7 @@ const findStableSetterReference = (node, scopes) => {
|
|
|
10669
10609
|
if (current !== node && (isNodeOfType(current, "FunctionDeclaration") || isNodeOfType(current, "FunctionExpression") || isNodeOfType(current, "ArrowFunctionExpression"))) return;
|
|
10670
10610
|
if (isNodeOfType(current, "Identifier")) {
|
|
10671
10611
|
const symbol = scopes.referenceFor(current)?.resolvedSymbol;
|
|
10672
|
-
if (symbol && isStableSetterLikeSymbol(symbol, scopes)
|
|
10612
|
+
if (symbol && isStableSetterLikeSymbol(symbol, scopes)) {
|
|
10673
10613
|
setterName = symbol.name;
|
|
10674
10614
|
return;
|
|
10675
10615
|
}
|
|
@@ -13562,7 +13502,7 @@ const jsCacheStorage = defineRule({
|
|
|
13562
13502
|
CallExpression(node) {
|
|
13563
13503
|
if (!isMemberProperty(node.callee, "getItem")) return;
|
|
13564
13504
|
const receiver = stripParenExpression(node.callee.object);
|
|
13565
|
-
if (!isNodeOfType(receiver, "Identifier") || !STORAGE_OBJECTS.has(receiver.name)) return;
|
|
13505
|
+
if (!isNodeOfType(receiver, "Identifier") || !STORAGE_OBJECTS$1.has(receiver.name)) return;
|
|
13566
13506
|
if (!isNodeOfType(node.arguments?.[0], "Literal")) return;
|
|
13567
13507
|
const storageReadCounts = storageReadCountStack[storageReadCountStack.length - 1];
|
|
13568
13508
|
const storageKey = String(node.arguments[0].value);
|
|
@@ -13829,11 +13769,6 @@ const jsEarlyExit = defineRule({
|
|
|
13829
13769
|
});
|
|
13830
13770
|
//#endregion
|
|
13831
13771
|
//#region src/plugin/rules/js-performance/js-flatmap-filter.ts
|
|
13832
|
-
const BOUNDED_PIPELINE_SOURCE_METHOD_NAMES = new Set(["slice", "split"]);
|
|
13833
|
-
const isBoundedPipelineSource = (node) => {
|
|
13834
|
-
const receiver = stripParenExpression(node);
|
|
13835
|
-
return isNodeOfType(receiver, "CallExpression") && isNodeOfType(receiver.callee, "MemberExpression") && isNodeOfType(receiver.callee.property, "Identifier") && BOUNDED_PIPELINE_SOURCE_METHOD_NAMES.has(receiver.callee.property.name);
|
|
13836
|
-
};
|
|
13837
13772
|
const jsFlatmapFilter = defineRule({
|
|
13838
13773
|
id: "js-flatmap-filter",
|
|
13839
13774
|
title: ".map().filter(Boolean) loops twice",
|
|
@@ -13851,7 +13786,6 @@ const jsFlatmapFilter = defineRule({
|
|
|
13851
13786
|
if (!isNodeOfType(innerCall, "CallExpression") || !isNodeOfType(innerCall.callee, "MemberExpression") || !isNodeOfType(innerCall.callee.property, "Identifier")) return;
|
|
13852
13787
|
if (innerCall.callee.property.name !== "map") return;
|
|
13853
13788
|
const receiver = stripParenExpression(innerCall.callee.object);
|
|
13854
|
-
if (receiver && isBoundedPipelineSource(receiver)) return;
|
|
13855
13789
|
if (receiver && isNodeOfType(receiver, "ArrayExpression")) {
|
|
13856
13790
|
const elements = receiver.elements ?? [];
|
|
13857
13791
|
if (elements.length > 0 && elements.length <= 8 && elements.every((element) => element == null || !isNodeOfType(element, "SpreadElement"))) return;
|
|
@@ -15787,40 +15721,6 @@ const isArrayVariableRenderedAsList = (declarator) => {
|
|
|
15787
15721
|
renderedAsListCache.set(declarator, didFindRenderingUse);
|
|
15788
15722
|
return didFindRenderingUse;
|
|
15789
15723
|
};
|
|
15790
|
-
const namedCallbackIteratorCallCache = /* @__PURE__ */ new WeakMap();
|
|
15791
|
-
const findNamedCallbackIteratorCall = (functionNode) => {
|
|
15792
|
-
const cached = namedCallbackIteratorCallCache.get(functionNode);
|
|
15793
|
-
if (cached !== void 0) return cached;
|
|
15794
|
-
const bindingIdentifier = getFunctionBindingIdentifier(functionNode);
|
|
15795
|
-
if (!bindingIdentifier) {
|
|
15796
|
-
namedCallbackIteratorCallCache.set(functionNode, null);
|
|
15797
|
-
return null;
|
|
15798
|
-
}
|
|
15799
|
-
const programRoot = findProgramRoot(functionNode);
|
|
15800
|
-
if (!programRoot) {
|
|
15801
|
-
namedCallbackIteratorCallCache.set(functionNode, null);
|
|
15802
|
-
return null;
|
|
15803
|
-
}
|
|
15804
|
-
let iteratorCall = null;
|
|
15805
|
-
walkAst(programRoot, (node) => {
|
|
15806
|
-
if (iteratorCall) return false;
|
|
15807
|
-
if (!isNodeOfType(node, "Identifier") || node === bindingIdentifier || node.name !== bindingIdentifier.name) return;
|
|
15808
|
-
const binding = findVariableInitializer(node, node.name);
|
|
15809
|
-
if (!binding || binding.bindingIdentifier !== bindingIdentifier) return;
|
|
15810
|
-
const callbackExpression = findTransparentExpressionRoot(node);
|
|
15811
|
-
const callExpression = callbackExpression.parent;
|
|
15812
|
-
if (!callExpression || !isNodeOfType(callExpression, "CallExpression")) return;
|
|
15813
|
-
const callee = callExpression.callee;
|
|
15814
|
-
if (!isNodeOfType(callee, "MemberExpression") || !isNodeOfType(callee.property, "Identifier") || !ITERATOR_METHOD_NAMES$1.has(callee.property.name)) return;
|
|
15815
|
-
const callbackIndex = callee.property.name === "from" ? 1 : 0;
|
|
15816
|
-
if (callExpression.arguments[callbackIndex] !== callbackExpression) return;
|
|
15817
|
-
if (isNonChildrenJsxAttributeValue(callExpression)) return;
|
|
15818
|
-
iteratorCall = callExpression;
|
|
15819
|
-
return false;
|
|
15820
|
-
});
|
|
15821
|
-
namedCallbackIteratorCallCache.set(functionNode, iteratorCall);
|
|
15822
|
-
return iteratorCall;
|
|
15823
|
-
};
|
|
15824
15724
|
const findEnclosingIteratorContext = (jsxNode) => {
|
|
15825
15725
|
let current = jsxNode;
|
|
15826
15726
|
let isOutsideContainingFunction = false;
|
|
@@ -15835,11 +15735,6 @@ const findEnclosingIteratorContext = (jsxNode) => {
|
|
|
15835
15735
|
const grandparent = parent.parent;
|
|
15836
15736
|
if (grandparent && isNodeOfType(grandparent, "Property")) return null;
|
|
15837
15737
|
if (isOutsideContainingFunction) return null;
|
|
15838
|
-
const namedCallbackIteratorCall = findNamedCallbackIteratorCall(parent);
|
|
15839
|
-
if (namedCallbackIteratorCall) return {
|
|
15840
|
-
kind: "iterator",
|
|
15841
|
-
callExpression: namedCallbackIteratorCall
|
|
15842
|
-
};
|
|
15843
15738
|
isOutsideContainingFunction = true;
|
|
15844
15739
|
} else if (isNodeOfType(parent, "ArrayExpression")) {
|
|
15845
15740
|
if (isOutsideContainingFunction) return null;
|
|
@@ -15883,10 +15778,7 @@ const resolveIterationItemName = (callExpression) => {
|
|
|
15883
15778
|
if (!isNodeOfType(callee, "MemberExpression")) return null;
|
|
15884
15779
|
if (!isNodeOfType(callee.property, "Identifier")) return null;
|
|
15885
15780
|
const targetArgIndex = callee.property.name === "from" ? 1 : 0;
|
|
15886
|
-
const
|
|
15887
|
-
if (!callbackArgument) return null;
|
|
15888
|
-
const unwrappedCallback = stripParenExpression(callbackArgument);
|
|
15889
|
-
const callback = isNodeOfType(unwrappedCallback, "Identifier") ? findVariableInitializer(unwrappedCallback, unwrappedCallback.name)?.initializer : unwrappedCallback;
|
|
15781
|
+
const callback = callExpression.arguments[targetArgIndex];
|
|
15890
15782
|
if (!callback || !isNodeOfType(callback, "ArrowFunctionExpression") && !isNodeOfType(callback, "FunctionExpression")) return null;
|
|
15891
15783
|
const firstParam = callback.params[0];
|
|
15892
15784
|
return firstParam && isNodeOfType(firstParam, "Identifier") ? firstParam.name : null;
|
|
@@ -22860,7 +22752,7 @@ const readsPostMountValueThroughLocals = (root, effectFn, options = {}, visitedL
|
|
|
22860
22752
|
};
|
|
22861
22753
|
//#endregion
|
|
22862
22754
|
//#region src/plugin/rules/state-and-effects/utils/collect-effect-state-write-facts.ts
|
|
22863
|
-
const SYNCHRONOUS_ITERATOR_METHOD_NAMES
|
|
22755
|
+
const SYNCHRONOUS_ITERATOR_METHOD_NAMES = new Set([
|
|
22864
22756
|
"every",
|
|
22865
22757
|
"filter",
|
|
22866
22758
|
"find",
|
|
@@ -23168,7 +23060,7 @@ const collectBoundedEffectExecutionFrames = (analysis, effectNode, currentFilena
|
|
|
23168
23060
|
const calleeName = getCallCalleeName$1(child);
|
|
23169
23061
|
const memberName = getStaticMemberName(callee);
|
|
23170
23062
|
const isDeferringCall = calleeName !== null && DEFERRING_CALLEE_NAMES.has(calleeName) || memberName !== null && DEFERRING_MEMBER_NAMES.has(memberName);
|
|
23171
|
-
const isIteratorCall = memberName !== null && SYNCHRONOUS_ITERATOR_METHOD_NAMES
|
|
23063
|
+
const isIteratorCall = memberName !== null && SYNCHRONOUS_ITERATOR_METHOD_NAMES.has(memberName) && isNodeOfType(callee, "MemberExpression");
|
|
23172
23064
|
const enqueueFrame = (callableNode, argumentsForCallable, isDeferred, introducedBindings, allowWithoutInvocationEvidence = false) => {
|
|
23173
23065
|
const callable = resolveWrappedCallable(analysis, callableNode);
|
|
23174
23066
|
if (!callable || callable.async === true || callable === effectFunction) return;
|
|
@@ -23405,15 +23297,10 @@ const isLocallyConstructedObjectMember = (reference, memberExpression) => isNode
|
|
|
23405
23297
|
const definitionNode = definition.node;
|
|
23406
23298
|
return isNodeOfType(definitionNode, "VariableDeclarator") && Boolean(definitionNode.init) && (isNodeOfType(definitionNode.init, "ObjectExpression") || isNodeOfType(definitionNode.init, "ArrayExpression"));
|
|
23407
23299
|
}) === true;
|
|
23408
|
-
const getUseRefDeclarator = (analysis, memberExpression) => {
|
|
23409
|
-
if (!isNodeOfType(memberExpression, "MemberExpression") || getStaticMemberName(memberExpression) !== "current" || !isNodeOfType(memberExpression.object, "Identifier")) return null;
|
|
23410
|
-
return getRef(analysis, memberExpression.object)?.resolved?.defs.map((definition) => definition.node).find((definitionNode) => isNodeOfType(definitionNode, "VariableDeclarator") && isNodeOfType(definitionNode.init, "CallExpression") && getCallCalleeName$1(definitionNode.init) === "useRef") ?? null;
|
|
23411
|
-
};
|
|
23412
23300
|
const collectValueEvidence = (analysis, expression, frame, remainingCallFrames, visitedBindings = /* @__PURE__ */ new Set()) => {
|
|
23413
23301
|
const node = stripParenExpression(expression);
|
|
23414
23302
|
const evidence = emptyEvidence();
|
|
23415
|
-
|
|
23416
|
-
if (!useRefDeclarator && (readsPostMountValue(node) || readsPostMountValueThroughLocals(node, frame.functionNode))) {
|
|
23303
|
+
if (readsPostMountValue(node) || readsPostMountValueThroughLocals(node, frame.functionNode)) {
|
|
23417
23304
|
evidence.readsExternalValue = true;
|
|
23418
23305
|
return evidence;
|
|
23419
23306
|
}
|
|
@@ -23455,11 +23342,7 @@ const collectValueEvidence = (analysis, expression, frame, remainingCallFrames,
|
|
|
23455
23342
|
evidence.hasUnknownSource = true;
|
|
23456
23343
|
return evidence;
|
|
23457
23344
|
}
|
|
23458
|
-
|
|
23459
|
-
if (nonInitializerWrites.length > 0) {
|
|
23460
|
-
const writtenIdentifier = nonInitializerWrites[0]?.identifier;
|
|
23461
|
-
const assignment = writtenIdentifier.parent;
|
|
23462
|
-
if (nonInitializerWrites.length === 1 && assignment && isNodeOfType(assignment, "AssignmentExpression") && assignment.operator === "=" && assignment.left === writtenIdentifier) return collectValueEvidence(analysis, assignment.right, frame, remainingCallFrames, visitedBindings);
|
|
23345
|
+
if (reference.resolved.references.some((candidateReference) => candidateReference.isWrite() && !candidateReference.init)) {
|
|
23463
23346
|
evidence.hasUnknownSource = true;
|
|
23464
23347
|
return evidence;
|
|
23465
23348
|
}
|
|
@@ -23475,40 +23358,6 @@ const collectValueEvidence = (analysis, expression, frame, remainingCallFrames,
|
|
|
23475
23358
|
return collectValueEvidence(analysis, initializer.init, frame, remainingCallFrames, visitedBindings);
|
|
23476
23359
|
}
|
|
23477
23360
|
if (isNodeOfType(node, "MemberExpression")) {
|
|
23478
|
-
if (getStaticMemberName(node) === "current" && isNodeOfType(node.object, "Identifier")) {
|
|
23479
|
-
const refBinding = getRef(analysis, node.object)?.resolved;
|
|
23480
|
-
const refDeclarator = useRefDeclarator;
|
|
23481
|
-
if (refBinding && refDeclarator && isNodeOfType(refDeclarator, "VariableDeclarator") && isNodeOfType(refDeclarator.init, "CallExpression")) {
|
|
23482
|
-
if (visitedBindings.has(refBinding)) {
|
|
23483
|
-
evidence.hasUnknownSource = true;
|
|
23484
|
-
return evidence;
|
|
23485
|
-
}
|
|
23486
|
-
const refVisitedBindings = new Set(visitedBindings);
|
|
23487
|
-
refVisitedBindings.add(refBinding);
|
|
23488
|
-
const initialValue = refDeclarator.init.arguments?.[0];
|
|
23489
|
-
if (initialValue) mergeEvidence(evidence, collectValueEvidence(analysis, initialValue, frame, remainingCallFrames, new Set(refVisitedBindings)));
|
|
23490
|
-
for (const candidateReference of refBinding.references) {
|
|
23491
|
-
if (candidateReference.init) continue;
|
|
23492
|
-
const identifier = candidateReference.identifier;
|
|
23493
|
-
const member = identifier.parent;
|
|
23494
|
-
if (!member || !isNodeOfType(member, "MemberExpression") || member.object !== identifier || getStaticMemberName(member) !== "current") {
|
|
23495
|
-
evidence.hasUnknownSource = true;
|
|
23496
|
-
continue;
|
|
23497
|
-
}
|
|
23498
|
-
const memberParent = member.parent;
|
|
23499
|
-
if (memberParent && isNodeOfType(memberParent, "AssignmentExpression") && memberParent.left === member) {
|
|
23500
|
-
if (memberParent.operator !== "=") {
|
|
23501
|
-
evidence.hasUnknownSource = true;
|
|
23502
|
-
continue;
|
|
23503
|
-
}
|
|
23504
|
-
mergeEvidence(evidence, collectValueEvidence(analysis, memberParent.right, frame, remainingCallFrames, new Set(refVisitedBindings)));
|
|
23505
|
-
continue;
|
|
23506
|
-
}
|
|
23507
|
-
if (memberParent && isNodeOfType(memberParent, "UpdateExpression")) evidence.hasUnknownSource = true;
|
|
23508
|
-
}
|
|
23509
|
-
return evidence;
|
|
23510
|
-
}
|
|
23511
|
-
}
|
|
23512
23361
|
if (isNodeOfType(node.object, "Identifier")) {
|
|
23513
23362
|
const objectReference = getRef(analysis, node.object);
|
|
23514
23363
|
if (objectReference && isLocallyConstructedObjectMember(objectReference, node)) {
|
|
@@ -29287,18 +29136,6 @@ const MUTATING_COLLECTION_METHOD_NAMES = new Set([
|
|
|
29287
29136
|
"set",
|
|
29288
29137
|
"add"
|
|
29289
29138
|
]);
|
|
29290
|
-
const SYNCHRONOUS_ITERATOR_METHOD_NAMES = new Set([
|
|
29291
|
-
"every",
|
|
29292
|
-
"filter",
|
|
29293
|
-
"find",
|
|
29294
|
-
"findIndex",
|
|
29295
|
-
"flatMap",
|
|
29296
|
-
"forEach",
|
|
29297
|
-
"map",
|
|
29298
|
-
"reduce",
|
|
29299
|
-
"reduceRight",
|
|
29300
|
-
"some"
|
|
29301
|
-
]);
|
|
29302
29139
|
const getMemberRootBindingName = (node, scope) => {
|
|
29303
29140
|
let currentNode = node;
|
|
29304
29141
|
while (isNodeOfType(currentNode, "MemberExpression")) currentNode = currentNode.object;
|
|
@@ -29352,26 +29189,6 @@ const addMutatingCollectionCallDependencies = (graph, expression, scope, eventHa
|
|
|
29352
29189
|
addDependencyNames(dependencyNames, controlDependencyNames);
|
|
29353
29190
|
addDependencies(graph, receiverRootName, dependencyNames);
|
|
29354
29191
|
};
|
|
29355
|
-
const addIteratorMutationDependencies = (graph, expression, scope, eventHandlerReferenceNames, controlDependencyNames) => {
|
|
29356
|
-
if (!isNodeOfType(expression, "CallExpression")) return;
|
|
29357
|
-
if (!isNodeOfType(expression.callee, "MemberExpression")) return;
|
|
29358
|
-
const methodName = getStaticMemberPropertyName(expression.callee);
|
|
29359
|
-
if (!methodName || !SYNCHRONOUS_ITERATOR_METHOD_NAMES.has(methodName)) return;
|
|
29360
|
-
const iteratorDependencyNames = collectScopedReferenceNames(expression.callee.object, scope, eventHandlerReferenceNames);
|
|
29361
|
-
addDependencyNames(iteratorDependencyNames, controlDependencyNames);
|
|
29362
|
-
for (const argument of expression.arguments ?? []) {
|
|
29363
|
-
if (!isNodeOfType(argument, "ArrowFunctionExpression") && !isNodeOfType(argument, "FunctionExpression")) continue;
|
|
29364
|
-
walkAst(argument.body, (node) => {
|
|
29365
|
-
if (node !== argument.body && isFunctionLike$1(node)) return false;
|
|
29366
|
-
if (!isNodeOfType(node, "CallExpression")) return;
|
|
29367
|
-
if (!isNodeOfType(node.callee, "MemberExpression")) return;
|
|
29368
|
-
const nestedMethodName = getStaticMemberPropertyName(node.callee);
|
|
29369
|
-
if (!nestedMethodName || !MUTATING_COLLECTION_METHOD_NAMES.has(nestedMethodName)) return;
|
|
29370
|
-
const receiverRootName = getMemberRootBindingName(node.callee.object, scope);
|
|
29371
|
-
if (receiverRootName) addDependencies(graph, receiverRootName, iteratorDependencyNames);
|
|
29372
|
-
});
|
|
29373
|
-
}
|
|
29374
|
-
};
|
|
29375
29192
|
const collectExpressionDependencies = (graph, expression, scope, eventHandlerReferenceNames, controlDependencyNames) => {
|
|
29376
29193
|
if (isNodeOfType(expression, "AssignmentExpression")) {
|
|
29377
29194
|
addAssignmentExpressionDependencies(graph, expression, scope, eventHandlerReferenceNames, controlDependencyNames);
|
|
@@ -29379,7 +29196,6 @@ const collectExpressionDependencies = (graph, expression, scope, eventHandlerRef
|
|
|
29379
29196
|
}
|
|
29380
29197
|
if (isNodeOfType(expression, "CallExpression")) {
|
|
29381
29198
|
addMutatingCollectionCallDependencies(graph, expression, scope, eventHandlerReferenceNames, controlDependencyNames);
|
|
29382
|
-
addIteratorMutationDependencies(graph, expression, scope, eventHandlerReferenceNames, controlDependencyNames);
|
|
29383
29199
|
return;
|
|
29384
29200
|
}
|
|
29385
29201
|
if (isNodeOfType(expression, "SequenceExpression")) {
|
|
@@ -30420,26 +30236,28 @@ const noGiantComponent = defineRule({
|
|
|
30420
30236
|
const lineCount = bodyNode.loc.end.line - bodyNode.loc.start.line + 1;
|
|
30421
30237
|
return lineCount > 300 ? lineCount : null;
|
|
30422
30238
|
};
|
|
30423
|
-
const reportOversizedComponent = (nameNode, componentName) => {
|
|
30239
|
+
const reportOversizedComponent = (nameNode, componentName, lineCount) => {
|
|
30424
30240
|
context.report({
|
|
30425
30241
|
node: nameNode,
|
|
30426
|
-
message: `Component "${componentName}" is
|
|
30242
|
+
message: `Component "${componentName}" is ${lineCount} lines long, which is hard to read & change. Split it into a few smaller components.`
|
|
30427
30243
|
});
|
|
30428
30244
|
};
|
|
30429
30245
|
return {
|
|
30430
30246
|
FunctionDeclaration(node) {
|
|
30431
30247
|
if (!node.id?.name || !isUppercaseName(node.id.name)) return;
|
|
30432
|
-
|
|
30248
|
+
const lineCount = getOversizedComponentLineCount(node);
|
|
30249
|
+
if (lineCount === null) return;
|
|
30433
30250
|
if (!functionContainsReactRenderOutput(node, context.scopes)) return;
|
|
30434
|
-
reportOversizedComponent(node.id, node.id.name);
|
|
30251
|
+
reportOversizedComponent(node.id, node.id.name, lineCount);
|
|
30435
30252
|
},
|
|
30436
30253
|
VariableDeclarator(node) {
|
|
30437
30254
|
if (!isNodeOfType(node.id, "Identifier") || !isUppercaseName(node.id.name)) return;
|
|
30438
30255
|
const functionNode = unwrapReactHocFunction(node.init);
|
|
30439
30256
|
if (!functionNode) return;
|
|
30440
|
-
|
|
30257
|
+
const lineCount = getOversizedComponentLineCount(functionNode);
|
|
30258
|
+
if (lineCount === null) return;
|
|
30441
30259
|
if (!functionContainsReactRenderOutput(functionNode, context.scopes)) return;
|
|
30442
|
-
reportOversizedComponent(node.id, node.id.name);
|
|
30260
|
+
reportOversizedComponent(node.id, node.id.name, lineCount);
|
|
30443
30261
|
}
|
|
30444
30262
|
};
|
|
30445
30263
|
}
|