oxlint-plugin-react-doctor 0.7.9-dev.61111f1 → 0.7.9-dev.9aa98b9
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 +46 -215
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6205,23 +6205,6 @@ const asyncDeferAwait = defineRule({
|
|
|
6205
6205
|
}
|
|
6206
6206
|
});
|
|
6207
6207
|
//#endregion
|
|
6208
|
-
//#region src/plugin/utils/expression-reads-pattern-binding.ts
|
|
6209
|
-
const expressionReadsPatternBinding = (expression, patterns, scopes) => {
|
|
6210
|
-
const bindingSymbolIds = /* @__PURE__ */ new Set();
|
|
6211
|
-
for (const pattern of patterns) walkAst(pattern, (child) => {
|
|
6212
|
-
if (!isNodeOfType(child, "Identifier")) return;
|
|
6213
|
-
const symbol = scopes.symbolFor(child);
|
|
6214
|
-
if (symbol?.bindingIdentifier === child) bindingSymbolIds.add(symbol.id);
|
|
6215
|
-
});
|
|
6216
|
-
let didReadBinding = false;
|
|
6217
|
-
walkAst(expression, (child) => {
|
|
6218
|
-
if (didReadBinding || !isNodeOfType(child, "Identifier")) return;
|
|
6219
|
-
const reference = scopes.referenceFor(child);
|
|
6220
|
-
if (reference?.flag !== "write" && reference?.resolvedSymbol && bindingSymbolIds.has(reference.resolvedSymbol.id)) didReadBinding = true;
|
|
6221
|
-
});
|
|
6222
|
-
return didReadBinding;
|
|
6223
|
-
};
|
|
6224
|
-
//#endregion
|
|
6225
6208
|
//#region src/plugin/utils/get-callee-identifier-trail.ts
|
|
6226
6209
|
const getCalleeIdentifierTrail = (call) => {
|
|
6227
6210
|
let entry = call;
|
|
@@ -6327,12 +6310,16 @@ const isInsideTransactionCallback = (node) => {
|
|
|
6327
6310
|
return false;
|
|
6328
6311
|
};
|
|
6329
6312
|
const reportIfIndependent = (statements, context) => {
|
|
6330
|
-
const
|
|
6313
|
+
const declaredNames = /* @__PURE__ */ new Set();
|
|
6331
6314
|
for (const statement of statements) {
|
|
6332
6315
|
const awaitArgument = getAwaitedCall(statement);
|
|
6333
6316
|
if (!awaitArgument) continue;
|
|
6334
|
-
|
|
6335
|
-
|
|
6317
|
+
let referencesEarlierResult = false;
|
|
6318
|
+
walkAst(awaitArgument, (child) => {
|
|
6319
|
+
if (isNodeOfType(child, "Identifier") && declaredNames.has(child.name)) referencesEarlierResult = true;
|
|
6320
|
+
});
|
|
6321
|
+
if (referencesEarlierResult) return;
|
|
6322
|
+
if (isNodeOfType(statement, "VariableDeclaration") && statement.declarations[0]?.id) collectPatternNames(statement.declarations[0].id, declaredNames);
|
|
6336
6323
|
}
|
|
6337
6324
|
context.report({
|
|
6338
6325
|
node: statements[0],
|
|
@@ -8476,21 +8463,10 @@ const isDestructuredReactApiBinding = (identifier, apiNames, scopes, options) =>
|
|
|
8476
8463
|
};
|
|
8477
8464
|
const isReactApiCall = (node, apiNames, scopes, options = {}) => {
|
|
8478
8465
|
if (!isNodeOfType(node, "CallExpression")) return false;
|
|
8479
|
-
|
|
8480
|
-
};
|
|
8481
|
-
const isReactApiCallee = (rawCallee, apiNames, scopes, options, visitedSymbolIds) => {
|
|
8482
|
-
const callee = stripParenExpression(rawCallee);
|
|
8483
|
-
if (options.resolveConditionalAliases && isNodeOfType(callee, "ConditionalExpression")) return isReactApiCallee(callee.consequent, apiNames, scopes, options, new Set(visitedSymbolIds)) && isReactApiCallee(callee.alternate, apiNames, scopes, options, new Set(visitedSymbolIds));
|
|
8466
|
+
const callee = stripParenExpression(node.callee);
|
|
8484
8467
|
if (isNodeOfType(callee, "Identifier")) {
|
|
8485
8468
|
if (isNamedReactApiImport(callee, apiNames, scopes, Boolean(options.resolveNamedAliases))) return true;
|
|
8486
8469
|
if (options.resolveNamedAliases && isDestructuredReactApiBinding(callee, apiNames, scopes, options)) return true;
|
|
8487
|
-
if (options.resolveConditionalAliases) {
|
|
8488
|
-
const symbol = scopes.symbolFor(callee);
|
|
8489
|
-
if (symbol?.kind === "const" && symbol.initializer && !visitedSymbolIds.has(symbol.id)) {
|
|
8490
|
-
visitedSymbolIds.add(symbol.id);
|
|
8491
|
-
return isReactApiCallee(symbol.initializer, apiNames, scopes, options, visitedSymbolIds);
|
|
8492
|
-
}
|
|
8493
|
-
}
|
|
8494
8470
|
return Boolean(options.allowUnboundBareCalls && includesApiName(apiNames, callee.name) && scopes.isGlobalReference(callee));
|
|
8495
8471
|
}
|
|
8496
8472
|
if (!isNodeOfType(callee, "MemberExpression") || !includesApiName(apiNames, getStaticPropertyName(callee) ?? "")) return false;
|
|
@@ -12347,10 +12323,6 @@ const isConstAliasOfGlobalArrayFrom = (node, scopes) => {
|
|
|
12347
12323
|
};
|
|
12348
12324
|
const executesDuringRender = (functionNode, scopes) => {
|
|
12349
12325
|
const parent = functionNode.parent;
|
|
12350
|
-
if (isNodeOfType(parent, "NewExpression")) {
|
|
12351
|
-
const callee = stripParenExpression(parent.callee);
|
|
12352
|
-
return Boolean(scopes && parent.arguments?.[0] === functionNode && isNodeOfType(callee, "Identifier") && callee.name === "Promise" && scopes.isGlobalReference(callee));
|
|
12353
|
-
}
|
|
12354
12326
|
if (!isNodeOfType(parent, "CallExpression")) return false;
|
|
12355
12327
|
if (parent.callee === functionNode) return true;
|
|
12356
12328
|
if ((scopes ? isReactApiCall(parent, REACT_RENDER_PHASE_HOOK_NAMES, scopes, { allowGlobalReactNamespace: true }) : isHookCall$2(parent, REACT_RENDER_PHASE_HOOK_NAMES)) && parent.arguments?.[0] === functionNode) return true;
|
|
@@ -29840,143 +29812,18 @@ const ARITHMETIC_KEY_OPERATORS = new Set([
|
|
|
29840
29812
|
"%"
|
|
29841
29813
|
]);
|
|
29842
29814
|
const bindingMutationResultsByProgram = /* @__PURE__ */ new WeakMap();
|
|
29843
|
-
const
|
|
29844
|
-
isNullish: null,
|
|
29845
|
-
isTruthy: null
|
|
29846
|
-
};
|
|
29847
|
-
const mergeStaticKeyBranchValues = (firstValue, secondValue) => ({
|
|
29848
|
-
isNullish: firstValue.isNullish === secondValue.isNullish ? firstValue.isNullish : null,
|
|
29849
|
-
isTruthy: firstValue.isTruthy === secondValue.isTruthy ? firstValue.isTruthy : null
|
|
29850
|
-
});
|
|
29851
|
-
const readStaticKeyBranchValue = (expression, depth) => {
|
|
29852
|
-
if (depth > TYPE_RESOLUTION_DEPTH_LIMIT) return null;
|
|
29853
|
-
const node = stripParenExpression(expression);
|
|
29854
|
-
if (isNodeOfType(node, "Literal")) return {
|
|
29855
|
-
isNullish: node.value === null,
|
|
29856
|
-
isTruthy: Boolean(node.value)
|
|
29857
|
-
};
|
|
29858
|
-
if (isNodeOfType(node, "ArrayExpression") || isNodeOfType(node, "ObjectExpression") || isNodeOfType(node, "ArrowFunctionExpression") || isNodeOfType(node, "FunctionExpression") || isNodeOfType(node, "ClassExpression") || isNodeOfType(node, "NewExpression")) return {
|
|
29859
|
-
isNullish: false,
|
|
29860
|
-
isTruthy: true
|
|
29861
|
-
};
|
|
29862
|
-
if (isNodeOfType(node, "TemplateLiteral")) return {
|
|
29863
|
-
isNullish: false,
|
|
29864
|
-
isTruthy: (node.quasis ?? []).some((quasi) => typeof quasi.value?.cooked === "string" && quasi.value.cooked.length > 0) ? true : null
|
|
29865
|
-
};
|
|
29866
|
-
if (isNodeOfType(node, "BinaryExpression")) return {
|
|
29867
|
-
isNullish: false,
|
|
29868
|
-
isTruthy: null
|
|
29869
|
-
};
|
|
29870
|
-
if (isNodeOfType(node, "Identifier")) {
|
|
29871
|
-
const binding = findVariableInitializer(node, node.name);
|
|
29872
|
-
if (!binding) {
|
|
29873
|
-
if (node.name === "undefined") return {
|
|
29874
|
-
isNullish: true,
|
|
29875
|
-
isTruthy: false
|
|
29876
|
-
};
|
|
29877
|
-
if (node.name === "NaN") return {
|
|
29878
|
-
isNullish: false,
|
|
29879
|
-
isTruthy: false
|
|
29880
|
-
};
|
|
29881
|
-
if (node.name === "Infinity") return {
|
|
29882
|
-
isNullish: false,
|
|
29883
|
-
isTruthy: true
|
|
29884
|
-
};
|
|
29885
|
-
return null;
|
|
29886
|
-
}
|
|
29887
|
-
if (!isConstDeclaredBinding(binding) || !binding.initializer) return null;
|
|
29888
|
-
const declarator = binding.bindingIdentifier.parent;
|
|
29889
|
-
if (!declarator || !isNodeOfType(declarator, "VariableDeclarator") || declarator.id !== binding.bindingIdentifier || declarator.init !== binding.initializer) return null;
|
|
29890
|
-
return readStaticKeyBranchValue(binding.initializer, depth + 1);
|
|
29891
|
-
}
|
|
29892
|
-
if (isNodeOfType(node, "CallExpression") && isNodeOfType(node.callee, "Identifier")) {
|
|
29893
|
-
if (!Boolean(findVariableInitializer(node.callee, node.callee.name)) && STRING_COERCION_FUNCTIONS.has(node.callee.name)) return {
|
|
29894
|
-
isNullish: false,
|
|
29895
|
-
isTruthy: null
|
|
29896
|
-
};
|
|
29897
|
-
}
|
|
29898
|
-
if (isNodeOfType(node, "UnaryExpression")) {
|
|
29899
|
-
if (node.operator === "void") return {
|
|
29900
|
-
isNullish: true,
|
|
29901
|
-
isTruthy: false
|
|
29902
|
-
};
|
|
29903
|
-
if (node.operator === "typeof") return {
|
|
29904
|
-
isNullish: false,
|
|
29905
|
-
isTruthy: true
|
|
29906
|
-
};
|
|
29907
|
-
if (node.operator === "+" || node.operator === "-" || node.operator === "~") return {
|
|
29908
|
-
isNullish: false,
|
|
29909
|
-
isTruthy: null
|
|
29910
|
-
};
|
|
29911
|
-
if (node.operator !== "!") return null;
|
|
29912
|
-
const argumentValue = readStaticKeyBranchValue(node.argument, depth + 1);
|
|
29913
|
-
if (!argumentValue || argumentValue.isTruthy === null) return null;
|
|
29914
|
-
return {
|
|
29915
|
-
isNullish: false,
|
|
29916
|
-
isTruthy: !argumentValue.isTruthy
|
|
29917
|
-
};
|
|
29918
|
-
}
|
|
29919
|
-
if (isNodeOfType(node, "SequenceExpression")) {
|
|
29920
|
-
const finalExpression = node.expressions.at(-1);
|
|
29921
|
-
return finalExpression ? readStaticKeyBranchValue(finalExpression, depth + 1) : null;
|
|
29922
|
-
}
|
|
29923
|
-
if (isNodeOfType(node, "LogicalExpression")) {
|
|
29924
|
-
const leftValue = readStaticKeyBranchValue(node.left, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE;
|
|
29925
|
-
if (node.operator === "&&" && leftValue.isTruthy !== null) return leftValue.isTruthy ? readStaticKeyBranchValue(node.right, depth + 1) : leftValue;
|
|
29926
|
-
if (node.operator === "||" && leftValue.isTruthy !== null) return leftValue.isTruthy ? leftValue : readStaticKeyBranchValue(node.right, depth + 1);
|
|
29927
|
-
if (node.operator === "??" && leftValue.isNullish !== null) return leftValue.isNullish ? readStaticKeyBranchValue(node.right, depth + 1) : leftValue;
|
|
29928
|
-
const rightValue = readStaticKeyBranchValue(node.right, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE;
|
|
29929
|
-
if (node.operator === "||") return {
|
|
29930
|
-
isNullish: rightValue.isNullish === false ? false : null,
|
|
29931
|
-
isTruthy: rightValue.isTruthy === true ? true : null
|
|
29932
|
-
};
|
|
29933
|
-
if (node.operator === "&&") return {
|
|
29934
|
-
isNullish: leftValue.isNullish === false && rightValue.isNullish === false ? false : null,
|
|
29935
|
-
isTruthy: rightValue.isTruthy === false ? false : null
|
|
29936
|
-
};
|
|
29937
|
-
return {
|
|
29938
|
-
isNullish: rightValue.isNullish === false ? false : null,
|
|
29939
|
-
isTruthy: leftValue.isTruthy !== null && leftValue.isTruthy === rightValue.isTruthy ? leftValue.isTruthy : null
|
|
29940
|
-
};
|
|
29941
|
-
}
|
|
29942
|
-
if (isNodeOfType(node, "ConditionalExpression")) {
|
|
29943
|
-
const testValue = readStaticKeyBranchValue(node.test, depth + 1);
|
|
29944
|
-
if (testValue?.isTruthy !== null && testValue?.isTruthy !== void 0) return readStaticKeyBranchValue(testValue.isTruthy ? node.consequent : node.alternate, depth + 1);
|
|
29945
|
-
return mergeStaticKeyBranchValues(readStaticKeyBranchValue(node.consequent, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE, readStaticKeyBranchValue(node.alternate, depth + 1) ?? UNKNOWN_STATIC_KEY_BRANCH_VALUE);
|
|
29946
|
-
}
|
|
29947
|
-
return null;
|
|
29948
|
-
};
|
|
29949
|
-
const extractCandidateIdentifiers = (expression, depth = 0) => {
|
|
29950
|
-
if (depth > TYPE_RESOLUTION_DEPTH_LIMIT) return [];
|
|
29815
|
+
const extractCandidateIdentifiers = (expression) => {
|
|
29951
29816
|
const node = stripParenExpression(expression);
|
|
29952
29817
|
if (isNodeOfType(node, "Identifier")) return [node];
|
|
29953
|
-
if (isNodeOfType(node, "UnaryExpression") && (node.operator === "-" || node.operator === "+" || node.operator === "~") && node.argument) return
|
|
29818
|
+
if (isNodeOfType(node, "UnaryExpression") && (node.operator === "-" || node.operator === "+" || node.operator === "~") && isNodeOfType(node.argument, "Identifier")) return [node.argument];
|
|
29954
29819
|
if (isNodeOfType(node, "TemplateLiteral")) {
|
|
29955
29820
|
const identifiers = [];
|
|
29956
|
-
for (const templateExpression of node.expressions ?? [])
|
|
29821
|
+
for (const templateExpression of node.expressions ?? []) if (isNodeOfType(templateExpression, "Identifier")) identifiers.push(templateExpression);
|
|
29957
29822
|
return identifiers;
|
|
29958
29823
|
}
|
|
29959
|
-
if (isNodeOfType(node, "LogicalExpression")) {
|
|
29960
|
-
const leftValue = readStaticKeyBranchValue(node.left, 0);
|
|
29961
|
-
if (leftValue) {
|
|
29962
|
-
if (node.operator === "&&" && leftValue.isTruthy !== null) return extractCandidateIdentifiers(leftValue.isTruthy ? node.right : node.left, depth + 1);
|
|
29963
|
-
if (node.operator === "||" && leftValue.isTruthy !== null) return extractCandidateIdentifiers(leftValue.isTruthy ? node.left : node.right, depth + 1);
|
|
29964
|
-
if (node.operator === "??" && leftValue.isNullish !== null) return extractCandidateIdentifiers(leftValue.isNullish ? node.right : node.left, depth + 1);
|
|
29965
|
-
}
|
|
29966
|
-
return [...extractCandidateIdentifiers(node.left, depth + 1), ...extractCandidateIdentifiers(node.right, depth + 1)];
|
|
29967
|
-
}
|
|
29968
|
-
if (isNodeOfType(node, "ConditionalExpression")) {
|
|
29969
|
-
const testValue = readStaticKeyBranchValue(node.test, 0);
|
|
29970
|
-
if (testValue && testValue.isTruthy !== null) return extractCandidateIdentifiers(testValue.isTruthy ? node.consequent : node.alternate, depth + 1);
|
|
29971
|
-
return [...extractCandidateIdentifiers(node.consequent, depth + 1), ...extractCandidateIdentifiers(node.alternate, depth + 1)];
|
|
29972
|
-
}
|
|
29973
|
-
if (isNodeOfType(node, "SequenceExpression")) {
|
|
29974
|
-
const finalExpression = node.expressions.at(-1);
|
|
29975
|
-
return finalExpression ? extractCandidateIdentifiers(finalExpression, depth + 1) : [];
|
|
29976
|
-
}
|
|
29977
29824
|
if (isNodeOfType(node, "CallExpression")) {
|
|
29978
|
-
if (isNodeOfType(node.callee, "MemberExpression") && isNodeOfType(node.callee.property, "Identifier") && node.callee.property.name === "toString") return
|
|
29979
|
-
if (isNodeOfType(node.callee, "Identifier") && STRING_COERCION_FUNCTIONS.has(node.callee.name) &&
|
|
29825
|
+
if (isNodeOfType(node.callee, "MemberExpression") && isNodeOfType(node.callee.object, "Identifier") && isNodeOfType(node.callee.property, "Identifier") && node.callee.property.name === "toString") return [node.callee.object];
|
|
29826
|
+
if (isNodeOfType(node.callee, "Identifier") && STRING_COERCION_FUNCTIONS.has(node.callee.name) && isNodeOfType(node.arguments?.[0], "Identifier")) return [node.arguments[0]];
|
|
29980
29827
|
return [];
|
|
29981
29828
|
}
|
|
29982
29829
|
if (isNodeOfType(node, "BinaryExpression")) {
|
|
@@ -32129,7 +31976,6 @@ const createStateTriggerReachability = ({ analysis, context, effectFunction }) =
|
|
|
32129
31976
|
};
|
|
32130
31977
|
//#endregion
|
|
32131
31978
|
//#region src/plugin/rules/state-and-effects/no-chain-state-updates.ts
|
|
32132
|
-
const APPLICABLE_EFFECT_HOOK_NAMES = new Set(["useEffect", "useLayoutEffect"]);
|
|
32133
31979
|
const getUseStateDeclarator = (ref) => (ref.resolved?.defs ?? []).map((def) => def.node).find((node) => isNodeOfType(node, "VariableDeclarator") && isNodeOfType(node.id, "ArrayPattern")) ?? null;
|
|
32134
31980
|
const isDeclaredWithin = (node, container) => {
|
|
32135
31981
|
let walker = node;
|
|
@@ -32181,12 +32027,7 @@ const noChainStateUpdates = defineRule({
|
|
|
32181
32027
|
tags: ["test-noise"],
|
|
32182
32028
|
recommendation: "Set all the related state together in the event handler that starts it, instead of having one useEffect react to a state change and set more state. See https://react.dev/learn/you-might-not-need-an-effect#chains-of-computations",
|
|
32183
32029
|
create: (context) => ({ CallExpression(node) {
|
|
32184
|
-
if (!
|
|
32185
|
-
allowGlobalReactNamespace: true,
|
|
32186
|
-
allowUnboundBareCalls: true,
|
|
32187
|
-
resolveConditionalAliases: true,
|
|
32188
|
-
resolveNamedAliases: true
|
|
32189
|
-
})) return;
|
|
32030
|
+
if (!isUseEffect(node)) return;
|
|
32190
32031
|
const analysis = getProgramAnalysis(node);
|
|
32191
32032
|
if (!analysis) return;
|
|
32192
32033
|
if (hasCleanup(analysis, node)) return;
|
|
@@ -43979,9 +43820,9 @@ const isInsideComponentContext = (node) => {
|
|
|
43979
43820
|
}
|
|
43980
43821
|
return false;
|
|
43981
43822
|
};
|
|
43982
|
-
const
|
|
43983
|
-
if (isFunctionLike$1(node)) return node;
|
|
43984
|
-
if (isNodeOfType(node, "VariableDeclarator") && node.init && isFunctionLike$1(node.init)) return node.init;
|
|
43823
|
+
const functionBodyOf = (node) => {
|
|
43824
|
+
if (isFunctionLike$1(node)) return node.body ?? null;
|
|
43825
|
+
if (isNodeOfType(node, "VariableDeclarator") && node.init && isFunctionLike$1(node.init)) return node.init.body ?? null;
|
|
43985
43826
|
return null;
|
|
43986
43827
|
};
|
|
43987
43828
|
const isHookCallee = (callee) => {
|
|
@@ -43989,43 +43830,23 @@ const isHookCallee = (callee) => {
|
|
|
43989
43830
|
if (isNodeOfType(callee, "MemberExpression") && !callee.computed && isNodeOfType(callee.object, "Identifier") && isUppercaseName(callee.object.name) && isNodeOfType(callee.property, "Identifier")) return isReactHookName(callee.property.name);
|
|
43990
43831
|
return false;
|
|
43991
43832
|
};
|
|
43992
|
-
const
|
|
43993
|
-
|
|
43994
|
-
|
|
43995
|
-
|
|
43996
|
-
|
|
43997
|
-
if (
|
|
43998
|
-
if (
|
|
43999
|
-
if (!isNodeOfType(child, "CallExpression") && !isNodeOfType(child, "NewExpression")) return;
|
|
44000
|
-
if (isNodeOfType(child, "CallExpression")) {
|
|
44001
|
-
if (isHookCallee(child.callee)) {
|
|
44002
|
-
didFindReachableHook = true;
|
|
44003
|
-
return false;
|
|
44004
|
-
}
|
|
44005
|
-
const calledFunction = resolveExactLocalFunction(child.callee, context.scopes);
|
|
44006
|
-
if (calledFunction && isAstDescendant(calledFunction, rootFunction) && containsReachableHookCall(calledFunction, rootFunction, context, visitedFunctions)) {
|
|
44007
|
-
didFindReachableHook = true;
|
|
44008
|
-
return false;
|
|
44009
|
-
}
|
|
44010
|
-
}
|
|
44011
|
-
for (const callArgument of child.arguments ?? []) {
|
|
44012
|
-
if (!executesDuringRender(callArgument, context.scopes)) continue;
|
|
44013
|
-
const callbackFunction = resolveExactLocalFunction(callArgument, context.scopes);
|
|
44014
|
-
if (callbackFunction && isAstDescendant(callbackFunction, rootFunction) && containsReachableHookCall(callbackFunction, rootFunction, context, visitedFunctions)) {
|
|
44015
|
-
didFindReachableHook = true;
|
|
44016
|
-
return false;
|
|
44017
|
-
}
|
|
44018
|
-
}
|
|
43833
|
+
const containsHookCall = (body) => {
|
|
43834
|
+
let found = false;
|
|
43835
|
+
walkAst(body, (child) => {
|
|
43836
|
+
if (found) return false;
|
|
43837
|
+
if (child !== body && isFunctionLike$1(child) && isComponentFunction$1(child)) return false;
|
|
43838
|
+
if (!isNodeOfType(child, "CallExpression")) return;
|
|
43839
|
+
if (isHookCallee(child.callee)) found = true;
|
|
44019
43840
|
});
|
|
44020
|
-
return
|
|
43841
|
+
return found;
|
|
44021
43842
|
};
|
|
44022
|
-
const isHookCallingRenderHelper = (symbol
|
|
43843
|
+
const isHookCallingRenderHelper = (symbol) => {
|
|
44023
43844
|
if (!symbol) return false;
|
|
44024
43845
|
const declaration = symbol.declarationNode;
|
|
44025
43846
|
if (!isNodeOfType(declaration, "FunctionDeclaration") && !isNodeOfType(declaration, "VariableDeclarator")) return false;
|
|
44026
|
-
const
|
|
44027
|
-
if (!
|
|
44028
|
-
return
|
|
43847
|
+
const body = functionBodyOf(declaration);
|
|
43848
|
+
if (!body) return false;
|
|
43849
|
+
return containsHookCall(body);
|
|
44029
43850
|
};
|
|
44030
43851
|
const noRenderInRender = defineRule({
|
|
44031
43852
|
id: "no-render-in-render",
|
|
@@ -44040,7 +43861,7 @@ const noRenderInRender = defineRule({
|
|
|
44040
43861
|
const calleeName = expression.callee.name;
|
|
44041
43862
|
if (!RENDER_FUNCTION_PATTERN.test(calleeName)) return;
|
|
44042
43863
|
if (!isInsideComponentContext(node)) return;
|
|
44043
|
-
if (!isHookCallingRenderHelper(context.scopes.symbolFor(expression.callee)
|
|
43864
|
+
if (!isHookCallingRenderHelper(context.scopes.symbolFor(expression.callee))) return;
|
|
44044
43865
|
context.report({
|
|
44045
43866
|
node: expression,
|
|
44046
43867
|
message: `"${calleeName}()" hides a component behind an inline call, so pull it into its own component and render it as JSX so React can track it.`
|
|
@@ -63023,19 +62844,29 @@ const serverNoMutableModuleState = defineRule({
|
|
|
63023
62844
|
});
|
|
63024
62845
|
//#endregion
|
|
63025
62846
|
//#region src/plugin/rules/server/server-sequential-independent-await.ts
|
|
62847
|
+
const collectDeclaredNames = (declaration) => {
|
|
62848
|
+
const names = /* @__PURE__ */ new Set();
|
|
62849
|
+
if (!isNodeOfType(declaration, "VariableDeclaration")) return names;
|
|
62850
|
+
for (const declarator of declaration.declarations ?? []) collectPatternNames(declarator.id, names);
|
|
62851
|
+
return names;
|
|
62852
|
+
};
|
|
63026
62853
|
const declarationStartsWithAwait = (declaration) => {
|
|
63027
62854
|
if (!isNodeOfType(declaration, "VariableDeclaration")) return false;
|
|
63028
62855
|
for (const declarator of declaration.declarations ?? []) if (isNodeOfType(declarator.init, "AwaitExpression")) return true;
|
|
63029
62856
|
return false;
|
|
63030
62857
|
};
|
|
63031
|
-
const
|
|
63032
|
-
if (
|
|
62858
|
+
const declarationReadsAnyName = (declaration, names) => {
|
|
62859
|
+
if (names.size === 0) return false;
|
|
63033
62860
|
if (!isNodeOfType(declaration, "VariableDeclaration")) return false;
|
|
62861
|
+
let didRead = false;
|
|
63034
62862
|
for (const declarator of declaration.declarations ?? []) {
|
|
63035
62863
|
if (!declarator.init) continue;
|
|
63036
|
-
|
|
62864
|
+
walkAst(declarator.init, (child) => {
|
|
62865
|
+
if (didRead) return;
|
|
62866
|
+
if (isNodeOfType(child, "Identifier") && names.has(child.name)) didRead = true;
|
|
62867
|
+
});
|
|
63037
62868
|
}
|
|
63038
|
-
return
|
|
62869
|
+
return didRead;
|
|
63039
62870
|
};
|
|
63040
62871
|
const GATE_LEADING_VERBS = new Set([
|
|
63041
62872
|
"require",
|
|
@@ -63109,11 +62940,11 @@ const serverSequentialIndependentAwait = defineRule({
|
|
|
63109
62940
|
const currentStatement = statements[statementIndex];
|
|
63110
62941
|
if (!isNodeOfType(currentStatement, "VariableDeclaration")) continue;
|
|
63111
62942
|
if (!declarationStartsWithAwait(currentStatement)) continue;
|
|
63112
|
-
const
|
|
62943
|
+
const declaredNames = collectDeclaredNames(currentStatement);
|
|
63113
62944
|
const nextStatement = statements[statementIndex + 1];
|
|
63114
62945
|
if (!isNodeOfType(nextStatement, "VariableDeclaration")) continue;
|
|
63115
62946
|
if (!declarationStartsWithAwait(nextStatement)) continue;
|
|
63116
|
-
if (
|
|
62947
|
+
if (declarationReadsAnyName(nextStatement, declaredNames)) continue;
|
|
63117
62948
|
if (declarationAwaitsExistingPromise(nextStatement)) continue;
|
|
63118
62949
|
if (declarationAwaitsRequestScopedCall(currentStatement) || declarationAwaitsRequestScopedCall(nextStatement)) continue;
|
|
63119
62950
|
if (declarationAwaitsGate(currentStatement, context)) continue;
|