oxlint-plugin-react-doctor 0.7.8-dev.9256423 → 0.7.8-dev.ece35b3
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 +2 -416
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22317,7 +22317,7 @@ const isReactSlotType = (typeNode, environment, activeDeclarations) => {
|
|
|
22317
22317
|
}
|
|
22318
22318
|
return environment.reactSlotTypeBindings.has(typeName);
|
|
22319
22319
|
};
|
|
22320
|
-
const getPropertyName
|
|
22320
|
+
const getPropertyName = (property) => {
|
|
22321
22321
|
if (!isNodeOfType(property, "TSPropertySignature") || property.computed) return null;
|
|
22322
22322
|
if (isNodeOfType(property.key, "Identifier")) return property.key.name;
|
|
22323
22323
|
if (isNodeOfType(property.key, "Literal") && typeof property.key.value === "string") return property.key.value;
|
|
@@ -22329,7 +22329,7 @@ const collectSlotPropertyNames = (propsType, environment, slotPropertyNames, act
|
|
|
22329
22329
|
if (isNodeOfType(propsType, "TSInterfaceDeclaration")) members = propsType.body.body;
|
|
22330
22330
|
if (members) {
|
|
22331
22331
|
for (const member of members) {
|
|
22332
|
-
const propertyName = getPropertyName
|
|
22332
|
+
const propertyName = getPropertyName(member);
|
|
22333
22333
|
if (!propertyName || !isNodeOfType(member, "TSPropertySignature")) continue;
|
|
22334
22334
|
const annotation = member.typeAnnotation;
|
|
22335
22335
|
if (annotation && isNodeOfType(annotation, "TSTypeAnnotation") && isReactSlotType(annotation.typeAnnotation, environment, /* @__PURE__ */ new Set())) slotPropertyNames.add(propertyName);
|
|
@@ -42992,31 +42992,6 @@ const noRenderReturnValue = defineRule({
|
|
|
42992
42992
|
});
|
|
42993
42993
|
//#endregion
|
|
42994
42994
|
//#region src/plugin/rules/state-and-effects/no-reset-all-state-on-prop-change.ts
|
|
42995
|
-
const SYNCHRONOUS_ARRAY_CALLBACK_METHOD_NAMES = new Set([
|
|
42996
|
-
"every",
|
|
42997
|
-
"filter",
|
|
42998
|
-
"find",
|
|
42999
|
-
"findIndex",
|
|
43000
|
-
"flatMap",
|
|
43001
|
-
"forEach",
|
|
43002
|
-
"map",
|
|
43003
|
-
"reduce",
|
|
43004
|
-
"reduceRight",
|
|
43005
|
-
"some"
|
|
43006
|
-
]);
|
|
43007
|
-
const createConstantFormula = (constantValue) => ({
|
|
43008
|
-
kind: "constant",
|
|
43009
|
-
constantValue
|
|
43010
|
-
});
|
|
43011
|
-
const createNotFormula = (formula) => ({
|
|
43012
|
-
kind: "not",
|
|
43013
|
-
left: formula
|
|
43014
|
-
});
|
|
43015
|
-
const createBinaryFormula = (kind, left, right) => ({
|
|
43016
|
-
kind,
|
|
43017
|
-
left,
|
|
43018
|
-
right
|
|
43019
|
-
});
|
|
43020
42995
|
const isUndefinedNode = (node) => {
|
|
43021
42996
|
if (node === null || node === void 0) return true;
|
|
43022
42997
|
return isNodeOfType(node, "Identifier") && node.name === "undefined";
|
|
@@ -43078,241 +43053,6 @@ const getLivePropExpressionIdentity = (analysis, context, node, visitedSymbolIds
|
|
|
43078
43053
|
}
|
|
43079
43054
|
return null;
|
|
43080
43055
|
};
|
|
43081
|
-
const getLivePropAtomKey = (identity) => `prop:${identity.propSymbolId}:${JSON.stringify(identity.memberPath)}:${identity.booleanNormalization}`;
|
|
43082
|
-
const getBooleanFormula$1 = (analysis, context, node, protectedSymbolIds, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
43083
|
-
const expression = stripParenExpression(node);
|
|
43084
|
-
if (isNodeOfType(expression, "Literal")) return createConstantFormula(Boolean(expression.value));
|
|
43085
|
-
if (isNodeOfType(expression, "Identifier")) {
|
|
43086
|
-
if (expression.name === "undefined" && context.scopes.isGlobalReference(expression)) return createConstantFormula(false);
|
|
43087
|
-
const symbol = context.scopes.symbolFor(expression);
|
|
43088
|
-
if (!symbol) return null;
|
|
43089
|
-
if (!protectedSymbolIds.has(symbol.id) && symbol.kind === "const" && !visitedSymbolIds.has(symbol.id) && isNodeOfType(symbol.declarationNode, "VariableDeclarator") && symbol.declarationNode.id === symbol.bindingIdentifier) {
|
|
43090
|
-
const initializer = getDirectConstInitializer(symbol);
|
|
43091
|
-
if (initializer) {
|
|
43092
|
-
visitedSymbolIds.add(symbol.id);
|
|
43093
|
-
const initializerFormula = getBooleanFormula$1(analysis, context, initializer, protectedSymbolIds, visitedSymbolIds);
|
|
43094
|
-
if (initializerFormula) return initializerFormula;
|
|
43095
|
-
}
|
|
43096
|
-
}
|
|
43097
|
-
return {
|
|
43098
|
-
kind: "atom",
|
|
43099
|
-
atomKey: `symbol:${symbol.id}`
|
|
43100
|
-
};
|
|
43101
|
-
}
|
|
43102
|
-
if (isNodeOfType(expression, "MemberExpression")) {
|
|
43103
|
-
const identity = getLivePropExpressionIdentity(analysis, context, expression);
|
|
43104
|
-
return identity ? {
|
|
43105
|
-
kind: "atom",
|
|
43106
|
-
atomKey: getLivePropAtomKey(identity)
|
|
43107
|
-
} : null;
|
|
43108
|
-
}
|
|
43109
|
-
if (isNodeOfType(expression, "UnaryExpression") && expression.operator === "!") {
|
|
43110
|
-
const argumentFormula = getBooleanFormula$1(analysis, context, expression.argument, protectedSymbolIds, visitedSymbolIds);
|
|
43111
|
-
return argumentFormula ? createNotFormula(argumentFormula) : null;
|
|
43112
|
-
}
|
|
43113
|
-
if (isNodeOfType(expression, "CallExpression") && isNodeOfType(expression.callee, "Identifier") && expression.callee.name === "Boolean" && context.scopes.isGlobalReference(expression.callee) && expression.arguments.length === 1 && !isNodeOfType(expression.arguments[0], "SpreadElement")) return getBooleanFormula$1(analysis, context, expression.arguments[0], protectedSymbolIds, visitedSymbolIds);
|
|
43114
|
-
if (isNodeOfType(expression, "LogicalExpression") && (expression.operator === "&&" || expression.operator === "||")) {
|
|
43115
|
-
const leftFormula = getBooleanFormula$1(analysis, context, expression.left, protectedSymbolIds, new Set(visitedSymbolIds));
|
|
43116
|
-
const rightFormula = getBooleanFormula$1(analysis, context, expression.right, protectedSymbolIds, new Set(visitedSymbolIds));
|
|
43117
|
-
if (!leftFormula || !rightFormula) return null;
|
|
43118
|
-
return createBinaryFormula(expression.operator === "&&" ? "and" : "or", leftFormula, rightFormula);
|
|
43119
|
-
}
|
|
43120
|
-
if (isNodeOfType(expression, "ConditionalExpression")) {
|
|
43121
|
-
const testFormula = getBooleanFormula$1(analysis, context, expression.test, protectedSymbolIds, new Set(visitedSymbolIds));
|
|
43122
|
-
const consequentFormula = getBooleanFormula$1(analysis, context, expression.consequent, protectedSymbolIds, new Set(visitedSymbolIds));
|
|
43123
|
-
const alternateFormula = getBooleanFormula$1(analysis, context, expression.alternate, protectedSymbolIds, new Set(visitedSymbolIds));
|
|
43124
|
-
if (!testFormula || !consequentFormula || !alternateFormula) return null;
|
|
43125
|
-
return createBinaryFormula("or", createBinaryFormula("and", testFormula, consequentFormula), createBinaryFormula("and", createNotFormula(testFormula), alternateFormula));
|
|
43126
|
-
}
|
|
43127
|
-
if (isNodeOfType(expression, "BinaryExpression") && (expression.operator === "===" || expression.operator === "==" || expression.operator === "!==" || expression.operator === "!=")) {
|
|
43128
|
-
const leftIsBoolean = isNodeOfType(expression.left, "Literal") && typeof expression.left.value === "boolean";
|
|
43129
|
-
if (leftIsBoolean === (isNodeOfType(expression.right, "Literal") && typeof expression.right.value === "boolean")) return null;
|
|
43130
|
-
const booleanLiteral = leftIsBoolean ? expression.left : expression.right;
|
|
43131
|
-
const comparedFormula = getBooleanFormula$1(analysis, context, leftIsBoolean ? expression.right : expression.left, protectedSymbolIds, visitedSymbolIds);
|
|
43132
|
-
if (!comparedFormula || !isNodeOfType(booleanLiteral, "Literal")) return null;
|
|
43133
|
-
return (expression.operator === "===" || expression.operator === "==" ? booleanLiteral.value : !booleanLiteral.value) ? comparedFormula : createNotFormula(comparedFormula);
|
|
43134
|
-
}
|
|
43135
|
-
return null;
|
|
43136
|
-
};
|
|
43137
|
-
const getRequiredTruthyConditions = (analysis, context, node, protectedSymbolIds) => {
|
|
43138
|
-
const formula = getBooleanFormula$1(analysis, context, node, protectedSymbolIds);
|
|
43139
|
-
if (formula) return [formula];
|
|
43140
|
-
const expression = stripParenExpression(node);
|
|
43141
|
-
if (!isNodeOfType(expression, "LogicalExpression") || expression.operator !== "&&") return [];
|
|
43142
|
-
return [...getRequiredTruthyConditions(analysis, context, expression.left, protectedSymbolIds), ...getRequiredTruthyConditions(analysis, context, expression.right, protectedSymbolIds)];
|
|
43143
|
-
};
|
|
43144
|
-
const evaluateBooleanFormula$1 = (formula, assignments) => {
|
|
43145
|
-
if (formula.kind === "constant") return formula.constantValue ?? null;
|
|
43146
|
-
if (formula.kind === "atom") return formula.atomKey === void 0 ? null : assignments.get(formula.atomKey) ?? null;
|
|
43147
|
-
if (formula.kind === "not") {
|
|
43148
|
-
if (!formula.left) return null;
|
|
43149
|
-
const value = evaluateBooleanFormula$1(formula.left, assignments);
|
|
43150
|
-
return value === null ? null : !value;
|
|
43151
|
-
}
|
|
43152
|
-
if (!formula.left || !formula.right) return null;
|
|
43153
|
-
const leftValue = evaluateBooleanFormula$1(formula.left, assignments);
|
|
43154
|
-
const rightValue = evaluateBooleanFormula$1(formula.right, assignments);
|
|
43155
|
-
if (formula.kind === "and") {
|
|
43156
|
-
if (leftValue === false || rightValue === false) return false;
|
|
43157
|
-
return leftValue === true && rightValue === true ? true : null;
|
|
43158
|
-
}
|
|
43159
|
-
if (leftValue === true || rightValue === true) return true;
|
|
43160
|
-
return leftValue === false && rightValue === false ? false : null;
|
|
43161
|
-
};
|
|
43162
|
-
const assignBooleanFact = (facts, atomKey, value) => {
|
|
43163
|
-
const existingValue = facts.assignments.get(atomKey);
|
|
43164
|
-
if (existingValue === void 0) {
|
|
43165
|
-
facts.assignments.set(atomKey, value);
|
|
43166
|
-
facts.didChange = true;
|
|
43167
|
-
} else if (existingValue !== value) facts.didConflict = true;
|
|
43168
|
-
};
|
|
43169
|
-
const addRequiredBooleanFacts = (formula, expectedValue, facts) => {
|
|
43170
|
-
const existingValue = evaluateBooleanFormula$1(formula, facts.assignments);
|
|
43171
|
-
if (existingValue !== null) {
|
|
43172
|
-
if (existingValue !== expectedValue) facts.didConflict = true;
|
|
43173
|
-
return;
|
|
43174
|
-
}
|
|
43175
|
-
if (formula.kind === "atom" && formula.atomKey !== void 0) {
|
|
43176
|
-
assignBooleanFact(facts, formula.atomKey, expectedValue);
|
|
43177
|
-
return;
|
|
43178
|
-
}
|
|
43179
|
-
if (formula.kind === "not" && formula.left) {
|
|
43180
|
-
addRequiredBooleanFacts(formula.left, !expectedValue, facts);
|
|
43181
|
-
return;
|
|
43182
|
-
}
|
|
43183
|
-
if (!formula.left || !formula.right) return;
|
|
43184
|
-
if (formula.kind === "and") {
|
|
43185
|
-
if (expectedValue) {
|
|
43186
|
-
addRequiredBooleanFacts(formula.left, true, facts);
|
|
43187
|
-
addRequiredBooleanFacts(formula.right, true, facts);
|
|
43188
|
-
return;
|
|
43189
|
-
}
|
|
43190
|
-
const leftValue = evaluateBooleanFormula$1(formula.left, facts.assignments);
|
|
43191
|
-
const rightValue = evaluateBooleanFormula$1(formula.right, facts.assignments);
|
|
43192
|
-
if (leftValue === true) addRequiredBooleanFacts(formula.right, false, facts);
|
|
43193
|
-
if (rightValue === true) addRequiredBooleanFacts(formula.left, false, facts);
|
|
43194
|
-
return;
|
|
43195
|
-
}
|
|
43196
|
-
if (!expectedValue) {
|
|
43197
|
-
addRequiredBooleanFacts(formula.left, false, facts);
|
|
43198
|
-
addRequiredBooleanFacts(formula.right, false, facts);
|
|
43199
|
-
return;
|
|
43200
|
-
}
|
|
43201
|
-
const leftValue = evaluateBooleanFormula$1(formula.left, facts.assignments);
|
|
43202
|
-
const rightValue = evaluateBooleanFormula$1(formula.right, facts.assignments);
|
|
43203
|
-
if (leftValue === false) addRequiredBooleanFacts(formula.right, true, facts);
|
|
43204
|
-
if (rightValue === false) addRequiredBooleanFacts(formula.left, true, facts);
|
|
43205
|
-
};
|
|
43206
|
-
const doConditionsImplyFormula = (conditions, target) => {
|
|
43207
|
-
const facts = {
|
|
43208
|
-
assignments: /* @__PURE__ */ new Map(),
|
|
43209
|
-
didConflict: false,
|
|
43210
|
-
didChange: true
|
|
43211
|
-
};
|
|
43212
|
-
while (facts.didChange && !facts.didConflict) {
|
|
43213
|
-
facts.didChange = false;
|
|
43214
|
-
for (const condition of conditions) addRequiredBooleanFacts(condition, true, facts);
|
|
43215
|
-
}
|
|
43216
|
-
return facts.didConflict || evaluateBooleanFormula$1(target, facts.assignments) === true;
|
|
43217
|
-
};
|
|
43218
|
-
const getFunctionBindingSymbol = (functionNode, scopes) => {
|
|
43219
|
-
if (isNodeOfType(functionNode, "FunctionDeclaration") && functionNode.id) return scopes.symbolFor(functionNode.id);
|
|
43220
|
-
const parent = functionNode.parent;
|
|
43221
|
-
if ((isNodeOfType(functionNode, "ArrowFunctionExpression") || isNodeOfType(functionNode, "FunctionExpression")) && isNodeOfType(parent, "VariableDeclarator") && parent.init === functionNode && isNodeOfType(parent.id, "Identifier")) return scopes.symbolFor(parent.id);
|
|
43222
|
-
return null;
|
|
43223
|
-
};
|
|
43224
|
-
const getComponentFunctionNode = (containingNode) => {
|
|
43225
|
-
if (isFunctionLike$1(containingNode)) return containingNode;
|
|
43226
|
-
if (!isNodeOfType(containingNode, "VariableDeclarator") || !containingNode.init) return null;
|
|
43227
|
-
const initializer = stripParenExpression(containingNode.init);
|
|
43228
|
-
if (isFunctionLike$1(initializer)) return initializer;
|
|
43229
|
-
if (!isNodeOfType(initializer, "CallExpression")) return null;
|
|
43230
|
-
const firstArgument = initializer.arguments[0];
|
|
43231
|
-
return firstArgument && !isNodeOfType(firstArgument, "SpreadElement") && isFunctionLike$1(firstArgument) ? firstArgument : null;
|
|
43232
|
-
};
|
|
43233
|
-
const isReferenceDirectlyCalled = (identifier) => {
|
|
43234
|
-
const unwrappedIdentifier = stripParenExpression(identifier);
|
|
43235
|
-
const parent = unwrappedIdentifier.parent;
|
|
43236
|
-
return isNodeOfType(parent, "CallExpression") && parent.callee === unwrappedIdentifier ? parent : null;
|
|
43237
|
-
};
|
|
43238
|
-
const getSynchronousCallbackCall = (functionNode) => {
|
|
43239
|
-
const callExpression = functionNode.parent;
|
|
43240
|
-
if (!isNodeOfType(callExpression, "CallExpression") || !callExpression.arguments.some((argument) => argument === functionNode) || !isNodeOfType(callExpression.callee, "MemberExpression")) return null;
|
|
43241
|
-
const methodName = getStaticMemberPropertyName(callExpression.callee);
|
|
43242
|
-
return methodName && SYNCHRONOUS_ARRAY_CALLBACK_METHOD_NAMES.has(methodName) ? callExpression : null;
|
|
43243
|
-
};
|
|
43244
|
-
const isNodeEvaluatedDuringRender = (node, componentNode, scopes, visitedFunctionSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
43245
|
-
const functionNode = findEnclosingFunction$1(node);
|
|
43246
|
-
if (!functionNode) return false;
|
|
43247
|
-
if (functionNode === componentNode) return true;
|
|
43248
|
-
const synchronousCallbackCall = getSynchronousCallbackCall(functionNode);
|
|
43249
|
-
if (synchronousCallbackCall) return isNodeEvaluatedDuringRender(synchronousCallbackCall, componentNode, scopes, visitedFunctionSymbolIds);
|
|
43250
|
-
if (executesDuringRender(functionNode, scopes)) return isNodeEvaluatedDuringRender(functionNode.parent ?? functionNode, componentNode, scopes, visitedFunctionSymbolIds);
|
|
43251
|
-
const functionSymbol = getFunctionBindingSymbol(functionNode, scopes);
|
|
43252
|
-
if (!functionSymbol || visitedFunctionSymbolIds.has(functionSymbol.id)) return false;
|
|
43253
|
-
visitedFunctionSymbolIds.add(functionSymbol.id);
|
|
43254
|
-
let callCount = 0;
|
|
43255
|
-
for (const reference of functionSymbol.references) {
|
|
43256
|
-
const callExpression = isReferenceDirectlyCalled(reference.identifier);
|
|
43257
|
-
if (!callExpression) return false;
|
|
43258
|
-
if (!isNodeEvaluatedDuringRender(callExpression, componentNode, scopes, new Set(visitedFunctionSymbolIds))) return false;
|
|
43259
|
-
callCount += 1;
|
|
43260
|
-
}
|
|
43261
|
-
return callCount > 0;
|
|
43262
|
-
};
|
|
43263
|
-
const isInlineJsxCallback = (functionNode) => {
|
|
43264
|
-
let ancestor = functionNode.parent;
|
|
43265
|
-
while (ancestor) {
|
|
43266
|
-
if (isNodeOfType(ancestor, "JSXAttribute")) return true;
|
|
43267
|
-
if (isFunctionLike$1(ancestor) || isNodeOfType(ancestor, "Program")) return false;
|
|
43268
|
-
ancestor = ancestor.parent;
|
|
43269
|
-
}
|
|
43270
|
-
return false;
|
|
43271
|
-
};
|
|
43272
|
-
const collectExposureConditions = (analysis, context, node, componentNode, protectedSymbolIds) => {
|
|
43273
|
-
const conditions = [];
|
|
43274
|
-
let child = node;
|
|
43275
|
-
let parent = node.parent;
|
|
43276
|
-
while (parent) {
|
|
43277
|
-
if (isNodeOfType(parent, "LogicalExpression") && parent.right === child) {
|
|
43278
|
-
if (parent.operator === "&&") conditions.push(...getRequiredTruthyConditions(analysis, context, parent.left, protectedSymbolIds));
|
|
43279
|
-
if (parent.operator === "||") {
|
|
43280
|
-
const leftFormula = getBooleanFormula$1(analysis, context, parent.left, protectedSymbolIds);
|
|
43281
|
-
if (leftFormula) conditions.push(createNotFormula(leftFormula));
|
|
43282
|
-
}
|
|
43283
|
-
} else if (isNodeOfType(parent, "ConditionalExpression")) {
|
|
43284
|
-
const testFormula = getBooleanFormula$1(analysis, context, parent.test, protectedSymbolIds);
|
|
43285
|
-
if (testFormula && parent.consequent === child) conditions.push(testFormula);
|
|
43286
|
-
if (testFormula && parent.alternate === child) conditions.push(createNotFormula(testFormula));
|
|
43287
|
-
} else if (isNodeOfType(parent, "IfStatement")) {
|
|
43288
|
-
const testFormula = getBooleanFormula$1(analysis, context, parent.test, protectedSymbolIds);
|
|
43289
|
-
if (testFormula && parent.consequent === child) conditions.push(testFormula);
|
|
43290
|
-
if (testFormula && parent.alternate === child) conditions.push(createNotFormula(testFormula));
|
|
43291
|
-
}
|
|
43292
|
-
if (parent === componentNode) break;
|
|
43293
|
-
if (isFunctionLike$1(parent) && parent !== componentNode && !isInlineJsxCallback(parent)) {
|
|
43294
|
-
const synchronousCallbackCall = getSynchronousCallbackCall(parent);
|
|
43295
|
-
if (synchronousCallbackCall) {
|
|
43296
|
-
child = synchronousCallbackCall;
|
|
43297
|
-
parent = synchronousCallbackCall.parent;
|
|
43298
|
-
continue;
|
|
43299
|
-
}
|
|
43300
|
-
const functionSymbol = getFunctionBindingSymbol(parent, context.scopes);
|
|
43301
|
-
if (functionSymbol?.references.length === 1) {
|
|
43302
|
-
const callExpression = isReferenceDirectlyCalled(functionSymbol.references[0].identifier);
|
|
43303
|
-
if (callExpression) {
|
|
43304
|
-
child = callExpression;
|
|
43305
|
-
parent = callExpression.parent;
|
|
43306
|
-
continue;
|
|
43307
|
-
}
|
|
43308
|
-
}
|
|
43309
|
-
break;
|
|
43310
|
-
}
|
|
43311
|
-
child = parent;
|
|
43312
|
-
parent = parent.parent;
|
|
43313
|
-
}
|
|
43314
|
-
return conditions;
|
|
43315
|
-
};
|
|
43316
43056
|
const isMountSnapshotInitializer = (context, node) => {
|
|
43317
43057
|
if (!isReactApiCall(node, "useMemo", context.scopes, { resolveNamedAliases: true }) || !isNodeOfType(node, "CallExpression")) return false;
|
|
43318
43058
|
const dependencies = node.arguments?.[1];
|
|
@@ -43388,158 +43128,6 @@ const countUseStates = (analysis, componentNode) => {
|
|
|
43388
43128
|
for (const ref of getDownstreamRefs(analysis, componentNode)) if (isState(analysis, ref)) stateVariables.add(ref.resolved);
|
|
43389
43129
|
return stateVariables.size;
|
|
43390
43130
|
};
|
|
43391
|
-
const getStateSymbolForSetter = (analysis, context, setterReference) => {
|
|
43392
|
-
const useStateDeclaration = getUseStateDecl(analysis, setterReference);
|
|
43393
|
-
if (!useStateDeclaration || !isNodeOfType(useStateDeclaration, "VariableDeclarator") || !isNodeOfType(useStateDeclaration.id, "ArrayPattern")) return null;
|
|
43394
|
-
const stateBinding = useStateDeclaration.id.elements[0];
|
|
43395
|
-
return stateBinding && isNodeOfType(stateBinding, "Identifier") ? context.scopes.symbolFor(stateBinding) : null;
|
|
43396
|
-
};
|
|
43397
|
-
const getPropertyName = (node) => {
|
|
43398
|
-
if (isNodeOfType(node, "Identifier")) return node.name;
|
|
43399
|
-
return isNodeOfType(node, "Literal") && typeof node.value === "string" ? node.value : null;
|
|
43400
|
-
};
|
|
43401
|
-
const isBooleanTypeNode = (node) => {
|
|
43402
|
-
if (!node) return false;
|
|
43403
|
-
if (isNodeOfType(node, "TSBooleanKeyword")) return true;
|
|
43404
|
-
if (!isNodeOfType(node, "TSUnionType")) return false;
|
|
43405
|
-
return node.types.every((typeNode) => isNodeOfType(typeNode, "TSBooleanKeyword") || isNodeOfType(typeNode, "TSUndefinedKeyword") || isNodeOfType(typeNode, "TSNullKeyword"));
|
|
43406
|
-
};
|
|
43407
|
-
const getBooleanPropertyType = (typeNode, propertyName, referenceNode) => {
|
|
43408
|
-
const unwrappedType = isNodeOfType(typeNode, "TSTypeAnnotation") ? typeNode.typeAnnotation : typeNode;
|
|
43409
|
-
if (isNodeOfType(unwrappedType, "TSTypeLiteral")) return unwrappedType.members.some((member) => isNodeOfType(member, "TSPropertySignature") && getPropertyName(member.key) === propertyName && isBooleanTypeNode(member.typeAnnotation?.typeAnnotation));
|
|
43410
|
-
if (!isNodeOfType(unwrappedType, "TSTypeReference") || !isNodeOfType(unwrappedType.typeName, "Identifier")) return false;
|
|
43411
|
-
const typeName = unwrappedType.typeName.name;
|
|
43412
|
-
if (hasEnclosingTypeParameterNamed(referenceNode, typeName)) return false;
|
|
43413
|
-
const programNode = findProgramNode(referenceNode);
|
|
43414
|
-
if (!isNodeOfType(programNode, "Program")) return false;
|
|
43415
|
-
const matchingInterfaces = programNode.body.flatMap((statement) => {
|
|
43416
|
-
const declaration = isNodeOfType(statement, "ExportNamedDeclaration") ? statement.declaration : statement;
|
|
43417
|
-
return isNodeOfType(declaration, "TSInterfaceDeclaration") && declaration.id.name === typeName ? [declaration] : [];
|
|
43418
|
-
});
|
|
43419
|
-
if (matchingInterfaces.length !== 1) return false;
|
|
43420
|
-
let sameNameTypeBindingCount = 0;
|
|
43421
|
-
walkAst(programNode, (candidate) => {
|
|
43422
|
-
const identifier = isNodeOfType(candidate, "TSInterfaceDeclaration") || isNodeOfType(candidate, "TSTypeAliasDeclaration") || isNodeOfType(candidate, "ClassDeclaration") || isNodeOfType(candidate, "ClassExpression") || isNodeOfType(candidate, "TSEnumDeclaration") ? candidate.id : isNodeOfType(candidate, "TSTypeParameter") ? candidate.name : null;
|
|
43423
|
-
if (isNodeOfType(identifier, "Identifier") && identifier.name === typeName) sameNameTypeBindingCount += 1;
|
|
43424
|
-
});
|
|
43425
|
-
if (sameNameTypeBindingCount !== 1) return false;
|
|
43426
|
-
return matchingInterfaces[0].body.body.some((member) => isNodeOfType(member, "TSPropertySignature") && getPropertyName(member.key) === propertyName && isBooleanTypeNode(member.typeAnnotation?.typeAnnotation));
|
|
43427
|
-
};
|
|
43428
|
-
const findProgramNode = (node) => {
|
|
43429
|
-
let currentNode = node;
|
|
43430
|
-
while (currentNode.parent) currentNode = currentNode.parent;
|
|
43431
|
-
return currentNode;
|
|
43432
|
-
};
|
|
43433
|
-
const hasBooleanBindingAnnotation = (symbol, identifier) => {
|
|
43434
|
-
const property = symbol.bindingIdentifier.parent;
|
|
43435
|
-
const objectPattern = property?.parent;
|
|
43436
|
-
if (!isNodeOfType(property, "Property") || !isNodeOfType(objectPattern, "ObjectPattern") || !objectPattern.typeAnnotation) return false;
|
|
43437
|
-
const propertyName = getPropertyName(property.key);
|
|
43438
|
-
return Boolean(propertyName && getBooleanPropertyType(objectPattern.typeAnnotation, propertyName, identifier));
|
|
43439
|
-
};
|
|
43440
|
-
const isBooleanExpression$1 = (context, node, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
43441
|
-
const expression = stripParenExpression(node);
|
|
43442
|
-
if (isNodeOfType(expression, "Literal")) return typeof expression.value === "boolean";
|
|
43443
|
-
if (isNodeOfType(expression, "UnaryExpression") && expression.operator === "!") return true;
|
|
43444
|
-
if (isNodeOfType(expression, "BinaryExpression")) return [
|
|
43445
|
-
"==",
|
|
43446
|
-
"===",
|
|
43447
|
-
"!=",
|
|
43448
|
-
"!==",
|
|
43449
|
-
"<",
|
|
43450
|
-
"<=",
|
|
43451
|
-
">",
|
|
43452
|
-
">="
|
|
43453
|
-
].includes(expression.operator);
|
|
43454
|
-
if (isNodeOfType(expression, "CallExpression") && isNodeOfType(expression.callee, "Identifier") && expression.callee.name === "Boolean" && context.scopes.isGlobalReference(expression.callee)) return true;
|
|
43455
|
-
if (isNodeOfType(expression, "LogicalExpression")) return isBooleanExpression$1(context, expression.left, new Set(visitedSymbolIds)) && isBooleanExpression$1(context, expression.right, new Set(visitedSymbolIds));
|
|
43456
|
-
if (isNodeOfType(expression, "ConditionalExpression")) return isBooleanExpression$1(context, expression.consequent, new Set(visitedSymbolIds)) && isBooleanExpression$1(context, expression.alternate, new Set(visitedSymbolIds));
|
|
43457
|
-
if (!isNodeOfType(expression, "Identifier")) return false;
|
|
43458
|
-
const symbol = context.scopes.symbolFor(expression);
|
|
43459
|
-
if (!symbol || visitedSymbolIds.has(symbol.id)) return false;
|
|
43460
|
-
if (hasBooleanBindingAnnotation(symbol, expression)) return true;
|
|
43461
|
-
visitedSymbolIds.add(symbol.id);
|
|
43462
|
-
const initializer = getDirectConstInitializer(symbol);
|
|
43463
|
-
return Boolean(initializer && isBooleanExpression$1(context, initializer, visitedSymbolIds));
|
|
43464
|
-
};
|
|
43465
|
-
const getPropDerivedDependencySymbols = (analysis, context, dependencyReferences) => {
|
|
43466
|
-
const symbolsById = /* @__PURE__ */ new Map();
|
|
43467
|
-
for (const dependencyReference of dependencyReferences) {
|
|
43468
|
-
if (!getUpstreamRefs(analysis, dependencyReference).some((upstreamReference) => isProp(analysis, upstreamReference))) continue;
|
|
43469
|
-
const symbol = context.scopes.symbolFor(dependencyReference.identifier);
|
|
43470
|
-
if (symbol) symbolsById.set(symbol.id, symbol);
|
|
43471
|
-
}
|
|
43472
|
-
return [...symbolsById.values()];
|
|
43473
|
-
};
|
|
43474
|
-
const getImpliedDependencyValue = (conditions, dependencyFormulas) => {
|
|
43475
|
-
const impliesTrue = dependencyFormulas.some((dependencyFormula) => doConditionsImplyFormula(conditions, dependencyFormula));
|
|
43476
|
-
if (impliesTrue === dependencyFormulas.some((dependencyFormula) => doConditionsImplyFormula(conditions, createNotFormula(dependencyFormula)))) return null;
|
|
43477
|
-
return impliesTrue;
|
|
43478
|
-
};
|
|
43479
|
-
const getSetterExposureConditions = (analysis, context, setterReference, componentNode, protectedSymbolIds) => {
|
|
43480
|
-
const functionNode = findEnclosingFunction$1(setterReference.identifier);
|
|
43481
|
-
if (!functionNode) return null;
|
|
43482
|
-
if (isInlineJsxCallback(functionNode)) return [collectExposureConditions(analysis, context, functionNode, componentNode, protectedSymbolIds)];
|
|
43483
|
-
const functionSymbol = getFunctionBindingSymbol(functionNode, context.scopes);
|
|
43484
|
-
if (!functionSymbol || functionSymbol.references.length === 0) return null;
|
|
43485
|
-
const conditionsByReference = [];
|
|
43486
|
-
for (const reference of functionSymbol.references) {
|
|
43487
|
-
if (isReferenceDirectlyCalled(reference.identifier)) return null;
|
|
43488
|
-
let ancestor = reference.identifier.parent;
|
|
43489
|
-
while (ancestor && !isNodeOfType(ancestor, "JSXAttribute") && !isFunctionLike$1(ancestor)) ancestor = ancestor.parent;
|
|
43490
|
-
if (!isNodeOfType(ancestor, "JSXAttribute")) return null;
|
|
43491
|
-
conditionsByReference.push(collectExposureConditions(analysis, context, reference.identifier, componentNode, protectedSymbolIds));
|
|
43492
|
-
}
|
|
43493
|
-
return conditionsByReference;
|
|
43494
|
-
};
|
|
43495
|
-
const areAllSetterWritesVisibilityGuarded = (analysis, context, componentNode, resetSetterReferences, dependencySymbolIds, dependencyFormulas, visibleDependencyValue) => {
|
|
43496
|
-
const resetIdentifiers = new Set(resetSetterReferences.map((setterReference) => setterReference.identifier));
|
|
43497
|
-
const setterVariables = new Set(resetSetterReferences.map((reference) => reference.resolved));
|
|
43498
|
-
for (const setterVariable of setterVariables) {
|
|
43499
|
-
if (!setterVariable) return false;
|
|
43500
|
-
for (const setterReference of setterVariable.references) {
|
|
43501
|
-
if (setterVariable.identifiers.some((identifier) => identifier === setterReference.identifier)) continue;
|
|
43502
|
-
if (resetIdentifiers.has(setterReference.identifier)) continue;
|
|
43503
|
-
if (!getCallExpr(setterReference)) return false;
|
|
43504
|
-
const conditionsByExposure = getSetterExposureConditions(analysis, context, setterReference, componentNode, dependencySymbolIds);
|
|
43505
|
-
if (!conditionsByExposure || conditionsByExposure.some((conditions) => getImpliedDependencyValue(conditions, dependencyFormulas) !== visibleDependencyValue)) return false;
|
|
43506
|
-
}
|
|
43507
|
-
}
|
|
43508
|
-
return true;
|
|
43509
|
-
};
|
|
43510
|
-
const areAllResetStateReadsHiddenUntilReset = (analysis, context, componentNode, setterReferences, dependencyReferences) => {
|
|
43511
|
-
if (dependencyReferences.length !== 1) return false;
|
|
43512
|
-
const dependencySymbols = getPropDerivedDependencySymbols(analysis, context, dependencyReferences);
|
|
43513
|
-
if (dependencySymbols.length === 0 || dependencySymbols.some((symbol) => !isBooleanExpression$1(context, symbol.bindingIdentifier) || symbol.references.some((reference) => reference.flag !== "read"))) return false;
|
|
43514
|
-
const dependencySymbolIds = new Set(dependencySymbols.map((symbol) => symbol.id));
|
|
43515
|
-
const dependencyFormulas = dependencySymbols.map((symbol) => ({
|
|
43516
|
-
kind: "atom",
|
|
43517
|
-
atomKey: `symbol:${symbol.id}`
|
|
43518
|
-
}));
|
|
43519
|
-
const resetStateSymbolsById = /* @__PURE__ */ new Map();
|
|
43520
|
-
for (const setterReference of setterReferences) {
|
|
43521
|
-
const stateSymbol = getStateSymbolForSetter(analysis, context, setterReference);
|
|
43522
|
-
if (!stateSymbol) return false;
|
|
43523
|
-
resetStateSymbolsById.set(stateSymbol.id, stateSymbol);
|
|
43524
|
-
}
|
|
43525
|
-
let visibleDependencyValue = null;
|
|
43526
|
-
for (const stateSymbol of resetStateSymbolsById.values()) {
|
|
43527
|
-
let exposedReadCount = 0;
|
|
43528
|
-
for (const reference of stateSymbol.references) {
|
|
43529
|
-
if (reference.flag === "write") continue;
|
|
43530
|
-
const isRenderRead = isNodeEvaluatedDuringRender(reference.identifier, componentNode, context.scopes);
|
|
43531
|
-
const functionNode = findEnclosingFunction$1(reference.identifier);
|
|
43532
|
-
if (!isRenderRead && functionNode && !isInlineJsxCallback(functionNode)) return false;
|
|
43533
|
-
const referenceDependencyValue = getImpliedDependencyValue(collectExposureConditions(analysis, context, reference.identifier, componentNode, dependencySymbolIds), dependencyFormulas);
|
|
43534
|
-
if (referenceDependencyValue === null) return false;
|
|
43535
|
-
if (visibleDependencyValue !== null && visibleDependencyValue !== referenceDependencyValue) return false;
|
|
43536
|
-
visibleDependencyValue = referenceDependencyValue;
|
|
43537
|
-
exposedReadCount += 1;
|
|
43538
|
-
}
|
|
43539
|
-
if (exposedReadCount === 0) return false;
|
|
43540
|
-
}
|
|
43541
|
-
return Boolean(resetStateSymbolsById.size > 0 && visibleDependencyValue !== null && areAllSetterWritesVisibilityGuarded(analysis, context, componentNode, setterReferences, dependencySymbolIds, dependencyFormulas, visibleDependencyValue));
|
|
43542
|
-
};
|
|
43543
43131
|
const findPropUsedToResetAllState = (analysis, context, effectFnRefs, depsRefs, useEffectNode, effectFn) => {
|
|
43544
43132
|
const stateSetterRefs = effectFnRefs.filter((ref) => isSyncStateSetterCall(analysis, ref, effectFn));
|
|
43545
43133
|
if (stateSetterRefs.length === 0) return null;
|
|
@@ -43547,8 +43135,6 @@ const findPropUsedToResetAllState = (analysis, context, effectFnRefs, depsRefs,
|
|
|
43547
43135
|
if (stateSetterRefs.every((setterRef) => effectFnRefs.some((otherRef) => otherRef !== setterRef && otherRef.resolved === setterRef.resolved && Boolean(getCallExpr(otherRef)) && !isSyncStateSetterCall(analysis, otherRef, effectFn)))) return null;
|
|
43548
43136
|
const containing = findContainingNode(analysis, useEffectNode);
|
|
43549
43137
|
if (new Set(stateSetterRefs.map((setterRef) => setterRef.resolved)).size !== countUseStates(analysis, containing)) return null;
|
|
43550
|
-
const componentFunctionNode = containing ? getComponentFunctionNode(containing) : null;
|
|
43551
|
-
if (componentFunctionNode && areAllResetStateReadsHiddenUntilReset(analysis, context, componentFunctionNode, stateSetterRefs, depsRefs)) return null;
|
|
43552
43138
|
for (const depRef of depsRefs) for (const upRef of getUpstreamRefs(analysis, depRef)) if (isProp(analysis, upRef)) return upRef;
|
|
43553
43139
|
return null;
|
|
43554
43140
|
};
|