oxlint-plugin-react-doctor 0.7.9-dev.d7d38d7 → 0.7.9-dev.d8a20e0
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 +167 -47
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19996,6 +19996,28 @@ const jsLengthCheckFirst = defineRule({
|
|
|
19996
19996
|
} })
|
|
19997
19997
|
});
|
|
19998
19998
|
//#endregion
|
|
19999
|
+
//#region src/plugin/utils/is-proven-global-namespace-reference.ts
|
|
20000
|
+
const isProvenGlobalObjectReference = (expression, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
20001
|
+
const strippedExpression = stripParenExpression(expression);
|
|
20002
|
+
if (!isNodeOfType(strippedExpression, "Identifier")) return false;
|
|
20003
|
+
if ((strippedExpression.name === "globalThis" || strippedExpression.name === "window" || strippedExpression.name === "self" || strippedExpression.name === "global") && scopes.isGlobalReference(strippedExpression)) return true;
|
|
20004
|
+
const symbol = scopes.symbolFor(strippedExpression);
|
|
20005
|
+
if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbolIds.has(symbol.id)) return false;
|
|
20006
|
+
visitedSymbolIds.add(symbol.id);
|
|
20007
|
+
return isProvenGlobalObjectReference(symbol.initializer, scopes, visitedSymbolIds);
|
|
20008
|
+
};
|
|
20009
|
+
const isProvenGlobalNamespaceReference = (expression, namespaceName, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
20010
|
+
const strippedExpression = stripParenExpression(expression);
|
|
20011
|
+
if (isNodeOfType(strippedExpression, "Identifier")) {
|
|
20012
|
+
if (strippedExpression.name === namespaceName && scopes.isGlobalReference(strippedExpression)) return true;
|
|
20013
|
+
const symbol = scopes.symbolFor(strippedExpression);
|
|
20014
|
+
if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbolIds.has(symbol.id)) return false;
|
|
20015
|
+
visitedSymbolIds.add(symbol.id);
|
|
20016
|
+
return isProvenGlobalNamespaceReference(symbol.initializer, namespaceName, scopes, visitedSymbolIds);
|
|
20017
|
+
}
|
|
20018
|
+
return isNodeOfType(strippedExpression, "MemberExpression") && getStaticPropertyName(strippedExpression) === namespaceName && isProvenGlobalObjectReference(strippedExpression.object, scopes);
|
|
20019
|
+
};
|
|
20020
|
+
//#endregion
|
|
19999
20021
|
//#region src/plugin/rules/js-performance/js-min-max-loop.ts
|
|
20000
20022
|
const builtinMutationByProgram = /* @__PURE__ */ new WeakMap();
|
|
20001
20023
|
const RUNTIMELESS_SYMBOL_KINDS = new Set(["ts-interface", "ts-type-alias"]);
|
|
@@ -20052,26 +20074,6 @@ const isSafeFreshNumericArray = (arrayExpression) => {
|
|
|
20052
20074
|
}
|
|
20053
20075
|
return !(didFindPositiveZero && didFindNegativeZero);
|
|
20054
20076
|
};
|
|
20055
|
-
const isGlobalObjectReference = (expression, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
|
|
20056
|
-
const strippedExpression = stripParenExpression(expression);
|
|
20057
|
-
if (!isNodeOfType(strippedExpression, "Identifier")) return false;
|
|
20058
|
-
if ((strippedExpression.name === "globalThis" || strippedExpression.name === "window" || strippedExpression.name === "self" || strippedExpression.name === "global") && scopes.isGlobalReference(strippedExpression)) return true;
|
|
20059
|
-
const symbol = scopes.symbolFor(strippedExpression);
|
|
20060
|
-
if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbols.has(symbol.id)) return false;
|
|
20061
|
-
visitedSymbols.add(symbol.id);
|
|
20062
|
-
return isGlobalObjectReference(symbol.initializer, scopes, visitedSymbols);
|
|
20063
|
-
};
|
|
20064
|
-
const resolvesToGlobalNamespace = (expression, namespaceName, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
|
|
20065
|
-
const strippedExpression = stripParenExpression(expression);
|
|
20066
|
-
if (isNodeOfType(strippedExpression, "Identifier")) {
|
|
20067
|
-
if (strippedExpression.name === namespaceName && scopes.isGlobalReference(strippedExpression)) return true;
|
|
20068
|
-
const symbol = scopes.symbolFor(strippedExpression);
|
|
20069
|
-
if (!symbol?.initializer || symbol.kind !== "const" || visitedSymbols.has(symbol.id)) return false;
|
|
20070
|
-
visitedSymbols.add(symbol.id);
|
|
20071
|
-
return resolvesToGlobalNamespace(symbol.initializer, namespaceName, scopes, visitedSymbols);
|
|
20072
|
-
}
|
|
20073
|
-
return isNodeOfType(strippedExpression, "MemberExpression") && getStaticPropertyName(strippedExpression) === namespaceName && isGlobalObjectReference(strippedExpression.object, scopes);
|
|
20074
|
-
};
|
|
20075
20077
|
const resolvesToGlobalMethod = (expression, namespaceName, methodNames, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
|
|
20076
20078
|
const strippedExpression = stripParenExpression(expression);
|
|
20077
20079
|
if (isNodeOfType(strippedExpression, "Identifier")) {
|
|
@@ -20080,7 +20082,7 @@ const resolvesToGlobalMethod = (expression, namespaceName, methodNames, scopes,
|
|
|
20080
20082
|
visitedSymbols.add(symbol.id);
|
|
20081
20083
|
return resolvesToGlobalMethod(symbol.initializer, namespaceName, methodNames, scopes, visitedSymbols);
|
|
20082
20084
|
}
|
|
20083
|
-
return isNodeOfType(strippedExpression, "MemberExpression") && methodNames.has(getStaticPropertyName(strippedExpression) ?? "") &&
|
|
20085
|
+
return isNodeOfType(strippedExpression, "MemberExpression") && methodNames.has(getStaticPropertyName(strippedExpression) ?? "") && isProvenGlobalNamespaceReference(strippedExpression.object, namespaceName, scopes);
|
|
20084
20086
|
};
|
|
20085
20087
|
const resolvesToNativeArrayPrototype = (expression, scopes, visitedSymbols = /* @__PURE__ */ new Set()) => {
|
|
20086
20088
|
const strippedExpression = stripParenExpression(expression);
|
|
@@ -20092,7 +20094,7 @@ const resolvesToNativeArrayPrototype = (expression, scopes, visitedSymbols = /*
|
|
|
20092
20094
|
}
|
|
20093
20095
|
if (isNodeOfType(strippedExpression, "MemberExpression")) {
|
|
20094
20096
|
const propertyName = getStaticPropertyName(strippedExpression);
|
|
20095
|
-
if (propertyName === "prototype") return
|
|
20097
|
+
if (propertyName === "prototype") return isProvenGlobalNamespaceReference(strippedExpression.object, "Array", scopes);
|
|
20096
20098
|
return propertyName === "__proto__" && isNodeOfType(stripParenExpression(strippedExpression.object), "ArrayExpression");
|
|
20097
20099
|
}
|
|
20098
20100
|
if (!isNodeOfType(strippedExpression, "CallExpression")) return false;
|
|
@@ -20103,23 +20105,23 @@ const resolvesToNativeArrayPrototype = (expression, scopes, visitedSymbols = /*
|
|
|
20103
20105
|
const isGlobalNamespaceReplacementTarget = (target, namespaceName, scopes) => {
|
|
20104
20106
|
const strippedTarget = stripParenExpression(target);
|
|
20105
20107
|
if (isNodeOfType(strippedTarget, "Identifier")) return strippedTarget.name === namespaceName && scopes.isGlobalReference(strippedTarget);
|
|
20106
|
-
return isNodeOfType(strippedTarget, "MemberExpression") && getStaticPropertyName(strippedTarget) === namespaceName &&
|
|
20108
|
+
return isNodeOfType(strippedTarget, "MemberExpression") && getStaticPropertyName(strippedTarget) === namespaceName && isProvenGlobalObjectReference(strippedTarget.object, scopes);
|
|
20107
20109
|
};
|
|
20108
20110
|
const isUnsafeBuiltinMemberTarget = (target, targetFunction, scopes) => {
|
|
20109
20111
|
const strippedTarget = stripParenExpression(target);
|
|
20110
20112
|
if (!isNodeOfType(strippedTarget, "MemberExpression")) return false;
|
|
20111
20113
|
const propertyName = getStaticPropertyName(strippedTarget);
|
|
20112
20114
|
if (resolvesToNativeArrayPrototype(strippedTarget.object, scopes)) return propertyName === null || propertyName === "sort";
|
|
20113
|
-
if (
|
|
20114
|
-
return
|
|
20115
|
+
if (isProvenGlobalNamespaceReference(strippedTarget.object, "Math", scopes)) return propertyName === null || propertyName === targetFunction;
|
|
20116
|
+
return isProvenGlobalObjectReference(strippedTarget.object, scopes) && (propertyName === null || propertyName === "Math");
|
|
20115
20117
|
};
|
|
20116
20118
|
const isUnsafeBuiltinMutationApiCall = (callExpression, targetFunction, scopes) => {
|
|
20117
20119
|
const target = callExpression.arguments[0];
|
|
20118
20120
|
if (!target) return false;
|
|
20119
20121
|
let propertyName = null;
|
|
20120
20122
|
if (resolvesToNativeArrayPrototype(target, scopes)) propertyName = "sort";
|
|
20121
|
-
else if (
|
|
20122
|
-
else if (
|
|
20123
|
+
else if (isProvenGlobalNamespaceReference(target, "Math", scopes)) propertyName = targetFunction;
|
|
20124
|
+
else if (isProvenGlobalObjectReference(target, scopes)) propertyName = "Math";
|
|
20123
20125
|
if (!propertyName) return false;
|
|
20124
20126
|
const canObjectExpressionSetProperty = (properties) => {
|
|
20125
20127
|
if (!isNodeOfType(properties, "ObjectExpression")) return true;
|
|
@@ -20170,7 +20172,7 @@ const hasUnsafeMathBinding = (node, scopes) => {
|
|
|
20170
20172
|
let scope = scopes.scopeFor(node);
|
|
20171
20173
|
while (scope) {
|
|
20172
20174
|
const symbol = scope.symbolsByName.get("Math");
|
|
20173
|
-
if (symbol && !RUNTIMELESS_SYMBOL_KINDS.has(symbol.kind)) return !(symbol.kind === "const" && symbol.initializer &&
|
|
20175
|
+
if (symbol && !RUNTIMELESS_SYMBOL_KINDS.has(symbol.kind)) return !(symbol.kind === "const" && symbol.initializer && isProvenGlobalNamespaceReference(symbol.initializer, "Math", scopes));
|
|
20174
20176
|
scope = scope.parent;
|
|
20175
20177
|
}
|
|
20176
20178
|
return false;
|
|
@@ -44369,11 +44371,110 @@ const isSameRefCurrentMember = (node, refSymbol, scopes) => {
|
|
|
44369
44371
|
return isNodeOfType(receiver, "Identifier") && resolveConstIdentifierAlias(receiver, scopes)?.id === refSymbol.id;
|
|
44370
44372
|
};
|
|
44371
44373
|
const isSameRefCurrentAlias = (node, refSymbol, scopes) => {
|
|
44372
|
-
|
|
44373
|
-
if (
|
|
44374
|
-
|
|
44374
|
+
const expression = stripParenExpression(node);
|
|
44375
|
+
if (isSameRefCurrentMember(expression, refSymbol, scopes)) return true;
|
|
44376
|
+
if (!isNodeOfType(expression, "Identifier")) return false;
|
|
44377
|
+
const aliasSymbol = scopes.symbolFor(expression);
|
|
44375
44378
|
return aliasSymbol?.kind === "const" && aliasSymbol.initializer !== null && isSameRefCurrentMember(stripParenExpression(aliasSymbol.initializer), refSymbol, scopes);
|
|
44376
44379
|
};
|
|
44380
|
+
const resolveImmutableInitializationValue = (node, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
44381
|
+
const expression = stripParenExpression(node);
|
|
44382
|
+
if (!isNodeOfType(expression, "Identifier")) return expression;
|
|
44383
|
+
const symbol = scopes.symbolFor(expression);
|
|
44384
|
+
if (!symbol || symbol.kind !== "const" || !symbol.initializer || symbol.references.some((reference) => reference.flag !== "read") || visitedSymbolIds.has(symbol.id)) return null;
|
|
44385
|
+
visitedSymbolIds.add(symbol.id);
|
|
44386
|
+
return resolveImmutableInitializationValue(symbol.initializer, scopes, visitedSymbolIds);
|
|
44387
|
+
};
|
|
44388
|
+
const isProvablyTruthyInitializationValue = (node, scopes) => {
|
|
44389
|
+
const expression = resolveImmutableInitializationValue(node, scopes);
|
|
44390
|
+
return Boolean(expression && (isNodeOfType(expression, "NewExpression") || isNodeOfType(expression, "ObjectExpression") || isNodeOfType(expression, "ArrayExpression") || isNodeOfType(expression, "ArrowFunctionExpression") || isNodeOfType(expression, "FunctionExpression") || isNodeOfType(expression, "ClassExpression")));
|
|
44391
|
+
};
|
|
44392
|
+
const getInitializationConstructorName = (node, scopes) => {
|
|
44393
|
+
const expression = resolveImmutableInitializationValue(node, scopes);
|
|
44394
|
+
if (!expression) return null;
|
|
44395
|
+
if (isNodeOfType(expression, "NewExpression")) {
|
|
44396
|
+
const callee = stripParenExpression(expression.callee);
|
|
44397
|
+
return isNodeOfType(callee, "Identifier") ? callee.name : null;
|
|
44398
|
+
}
|
|
44399
|
+
return null;
|
|
44400
|
+
};
|
|
44401
|
+
const isClosedTruthyTypeDomain = (typeNode, initializationValue, scopes) => {
|
|
44402
|
+
const initializationExpression = stripParenExpression(initializationValue);
|
|
44403
|
+
if (isNodeOfType(typeNode, "TSTypeLiteral")) return isNodeOfType(initializationExpression, "ObjectExpression");
|
|
44404
|
+
if (isNodeOfType(typeNode, "TSArrayType") || isNodeOfType(typeNode, "TSTupleType")) return isNodeOfType(initializationExpression, "ArrayExpression");
|
|
44405
|
+
if (isNodeOfType(typeNode, "TSFunctionType") || isNodeOfType(typeNode, "TSConstructorType")) return isNodeOfType(initializationExpression, "ArrowFunctionExpression") || isNodeOfType(initializationExpression, "FunctionExpression") || isNodeOfType(initializationExpression, "ClassExpression");
|
|
44406
|
+
if (isNodeOfType(typeNode, "TSObjectKeyword")) return true;
|
|
44407
|
+
if (!isNodeOfType(typeNode, "TSTypeReference")) return false;
|
|
44408
|
+
const typeName = typeNode.typeName;
|
|
44409
|
+
return isNodeOfType(typeName, "Identifier") && typeName.name === getInitializationConstructorName(initializationExpression, scopes);
|
|
44410
|
+
};
|
|
44411
|
+
const refHasClosedFalsySentinelDomain = (refSymbol, initializationValue, scopes) => {
|
|
44412
|
+
const initializer = refSymbol.initializer ? stripParenExpression(refSymbol.initializer) : null;
|
|
44413
|
+
if (!initializer || !isNodeOfType(initializer, "CallExpression")) return false;
|
|
44414
|
+
const [initialValue] = initializer.arguments ?? [];
|
|
44415
|
+
if (!initialValue || isNodeOfType(initialValue, "SpreadElement") || !isEmptySentinel(initialValue, scopes)) return false;
|
|
44416
|
+
const [declaredType] = initializer.typeArguments?.params ?? [];
|
|
44417
|
+
if (!declaredType || !isNodeOfType(declaredType, "TSUnionType")) return false;
|
|
44418
|
+
let hasEmptySentinel = false;
|
|
44419
|
+
let hasTruthyDomain = false;
|
|
44420
|
+
for (const memberType of declaredType.types ?? []) {
|
|
44421
|
+
if (isNodeOfType(memberType, "TSNullKeyword") || isNodeOfType(memberType, "TSUndefinedKeyword")) {
|
|
44422
|
+
hasEmptySentinel = true;
|
|
44423
|
+
continue;
|
|
44424
|
+
}
|
|
44425
|
+
if (!isClosedTruthyTypeDomain(memberType, initializationValue, scopes)) return false;
|
|
44426
|
+
hasTruthyDomain = true;
|
|
44427
|
+
}
|
|
44428
|
+
return hasEmptySentinel && hasTruthyDomain;
|
|
44429
|
+
};
|
|
44430
|
+
const isSafeRefIdentifierUse = (identifier) => {
|
|
44431
|
+
const expressionRoot = findTransparentExpressionRoot(identifier);
|
|
44432
|
+
const parent = expressionRoot.parent;
|
|
44433
|
+
if (parent && isNodeOfType(parent, "VariableDeclarator") && parent.id === expressionRoot && parent.parent !== null && isNodeOfType(parent.parent, "VariableDeclaration") && parent.parent.kind === "const") return true;
|
|
44434
|
+
if (parent && isNodeOfType(parent, "MemberExpression") && parent.object === expressionRoot && getStaticPropertyName(parent) === "current") return true;
|
|
44435
|
+
if (!parent || !isNodeOfType(parent, "VariableDeclarator") || parent.init !== expressionRoot) return false;
|
|
44436
|
+
return isNodeOfType(parent.id, "Identifier") && parent.parent !== null && isNodeOfType(parent.parent, "VariableDeclaration") && parent.parent.kind === "const";
|
|
44437
|
+
};
|
|
44438
|
+
const refDoesNotEscape = (branchRoot, refSymbol, scopes) => {
|
|
44439
|
+
let didEscape = false;
|
|
44440
|
+
walkAst(branchRoot, (child) => {
|
|
44441
|
+
if (didEscape) return false;
|
|
44442
|
+
if (!isNodeOfType(child, "Identifier")) return;
|
|
44443
|
+
if (resolveConstIdentifierAlias(child, scopes)?.id !== refSymbol.id) return;
|
|
44444
|
+
if (child === refSymbol.bindingIdentifier || isSafeRefIdentifierUse(child)) return;
|
|
44445
|
+
didEscape = true;
|
|
44446
|
+
return false;
|
|
44447
|
+
});
|
|
44448
|
+
return !didEscape;
|
|
44449
|
+
};
|
|
44450
|
+
const expressionContainsRefCurrent = (expression, refSymbol, scopes) => {
|
|
44451
|
+
let didFindRefCurrent = false;
|
|
44452
|
+
walkAst(expression, (child) => {
|
|
44453
|
+
if (didFindRefCurrent) return false;
|
|
44454
|
+
if (resolveReactRefSymbol(child, scopes)?.id !== refSymbol.id) return;
|
|
44455
|
+
didFindRefCurrent = true;
|
|
44456
|
+
return false;
|
|
44457
|
+
});
|
|
44458
|
+
return didFindRefCurrent;
|
|
44459
|
+
};
|
|
44460
|
+
const hasNoCompetingRefCurrentWrite = (branchRoot, assignmentExpression, refSymbol, scopes) => {
|
|
44461
|
+
let writeCount = 0;
|
|
44462
|
+
walkAst(branchRoot, (child) => {
|
|
44463
|
+
if (writeCount > 1) return false;
|
|
44464
|
+
if (isNodeOfType(child, "AssignmentExpression")) {
|
|
44465
|
+
if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
|
|
44466
|
+
return;
|
|
44467
|
+
}
|
|
44468
|
+
if (isNodeOfType(child, "UpdateExpression") || isNodeOfType(child, "UnaryExpression") && child.operator === "delete") {
|
|
44469
|
+
if (expressionContainsRefCurrent(child.argument, refSymbol, scopes)) writeCount++;
|
|
44470
|
+
return;
|
|
44471
|
+
}
|
|
44472
|
+
if (isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement")) {
|
|
44473
|
+
if (expressionContainsRefCurrent(child.left, refSymbol, scopes)) writeCount++;
|
|
44474
|
+
}
|
|
44475
|
+
});
|
|
44476
|
+
return writeCount === 1 && expressionContainsRefCurrent(assignmentExpression.left, refSymbol, scopes);
|
|
44477
|
+
};
|
|
44377
44478
|
const isEmptySentinel = (node, scopes) => isNodeOfType(node, "Literal") && node.value === null || isNodeOfType(node, "Identifier") && node.name === "undefined" && scopes.isGlobalReference(node);
|
|
44378
44479
|
const hasRepeatedExecutionAncestor = (node, stop) => {
|
|
44379
44480
|
let ancestor = node.parent;
|
|
@@ -44422,18 +44523,22 @@ const hasNoPriorCoExecutableWrite = (assignmentExpression, branchRoot, refSymbol
|
|
|
44422
44523
|
const isDocumentedLazyInitialization = (assignmentExpression, refSymbol, scopes) => {
|
|
44423
44524
|
if (assignmentExpression.operator === "??=" || assignmentExpression.operator === "||=") return true;
|
|
44424
44525
|
if (assignmentExpression.operator !== "=") return false;
|
|
44526
|
+
const renderOwner = findRenderPhaseComponentOrHook(assignmentExpression, scopes);
|
|
44527
|
+
if (!renderOwner) return false;
|
|
44425
44528
|
let descendant = assignmentExpression;
|
|
44426
44529
|
let ancestor = descendant.parent;
|
|
44427
44530
|
while (ancestor) {
|
|
44428
|
-
|
|
44531
|
+
const test = isNodeOfType(ancestor, "IfStatement") ? stripParenExpression(ancestor.test) : null;
|
|
44532
|
+
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;
|
|
44533
|
+
if (isNodeOfType(ancestor, "IfStatement") && isNodeOfType(test, "BinaryExpression") && [
|
|
44429
44534
|
"===",
|
|
44430
44535
|
"==",
|
|
44431
44536
|
"!==",
|
|
44432
44537
|
"!="
|
|
44433
|
-
].includes(
|
|
44434
|
-
const { left, right } =
|
|
44538
|
+
].includes(test.operator)) {
|
|
44539
|
+
const { left, right } = test;
|
|
44435
44540
|
const comparesEmptySentinel = isSameRefCurrentAlias(left, refSymbol, scopes) && isEmptySentinel(right, scopes) || isSameRefCurrentAlias(right, refSymbol, scopes) && isEmptySentinel(left, scopes);
|
|
44436
|
-
const guardedBranch =
|
|
44541
|
+
const guardedBranch = test.operator === "===" || test.operator === "==" ? ancestor.consequent : ancestor.alternate;
|
|
44437
44542
|
if (comparesEmptySentinel && guardedBranch === descendant && guardedBranch && !hasRepeatedExecutionAncestor(assignmentExpression, guardedBranch) && hasNoPriorCoExecutableWrite(assignmentExpression, guardedBranch, refSymbol, scopes)) return true;
|
|
44438
44543
|
}
|
|
44439
44544
|
descendant = ancestor;
|
|
@@ -51558,6 +51663,31 @@ const preferModuleScopePureFunction = defineRule({
|
|
|
51558
51663
|
}
|
|
51559
51664
|
});
|
|
51560
51665
|
//#endregion
|
|
51666
|
+
//#region src/plugin/utils/get-require-call-source.ts
|
|
51667
|
+
const getRequireCallSource = (expression) => {
|
|
51668
|
+
const unwrappedExpression = stripParenExpression(expression);
|
|
51669
|
+
if (isNodeOfType(unwrappedExpression, "MemberExpression")) return getRequireCallSource(unwrappedExpression.object);
|
|
51670
|
+
if (!isNodeOfType(unwrappedExpression, "CallExpression")) return null;
|
|
51671
|
+
if (!isNodeOfType(unwrappedExpression.callee, "Identifier") || unwrappedExpression.callee.name !== "require") return null;
|
|
51672
|
+
const [firstArgument] = unwrappedExpression.arguments ?? [];
|
|
51673
|
+
if (!firstArgument || !isNodeOfType(firstArgument, "Literal")) return null;
|
|
51674
|
+
return typeof firstArgument.value === "string" ? firstArgument.value : null;
|
|
51675
|
+
};
|
|
51676
|
+
//#endregion
|
|
51677
|
+
//#region src/plugin/utils/is-proven-node-crypto-namespace-reference.ts
|
|
51678
|
+
const NODE_CRYPTO_MODULE_SOURCES = new Set(["crypto", "node:crypto"]);
|
|
51679
|
+
const isProvenNodeCryptoNamespaceReference = (expression, scopes) => {
|
|
51680
|
+
const identifier = stripParenExpression(expression);
|
|
51681
|
+
if (!isNodeOfType(identifier, "Identifier")) return false;
|
|
51682
|
+
const symbol = resolveConstIdentifierAlias(identifier, scopes);
|
|
51683
|
+
if (!symbol) return false;
|
|
51684
|
+
if (symbol.kind === "import") {
|
|
51685
|
+
const importBinding = getImportBindingForName(identifier, symbol.name);
|
|
51686
|
+
return Boolean(importBinding && NODE_CRYPTO_MODULE_SOURCES.has(importBinding.source));
|
|
51687
|
+
}
|
|
51688
|
+
return Boolean(symbol.kind === "const" && symbol.initializer && NODE_CRYPTO_MODULE_SOURCES.has(getRequireCallSource(symbol.initializer) ?? ""));
|
|
51689
|
+
};
|
|
51690
|
+
//#endregion
|
|
51561
51691
|
//#region src/plugin/rules/architecture/prefer-module-scope-static-value.ts
|
|
51562
51692
|
const MUTATING_RECEIVER_METHOD_NAMES = new Set([...MUTATING_ARRAY_METHODS, ...MUTATING_COLLECTION_METHODS]);
|
|
51563
51693
|
const isMutationContext = (referenceIdentifier) => {
|
|
@@ -51671,9 +51801,9 @@ const isImpureCall = (node, scopes) => {
|
|
|
51671
51801
|
const callee = node.callee;
|
|
51672
51802
|
if (isNodeOfType(callee, "Identifier")) return isImpureBareCallee(callee, scopes);
|
|
51673
51803
|
if (!isNodeOfType(callee, "MemberExpression") || callee.computed) return false;
|
|
51674
|
-
if (!isNodeOfType(callee.object, "Identifier")) return false;
|
|
51675
51804
|
if (!isNodeOfType(callee.property, "Identifier")) return false;
|
|
51676
|
-
|
|
51805
|
+
for (const [receiverName, receiverMethodNames] of IMPURE_MEMBER_RECEIVERS) if (receiverMethodNames.has(callee.property.name) && (isProvenGlobalNamespaceReference(callee.object, receiverName, scopes) || receiverName === "crypto" && isProvenNodeCryptoNamespaceReference(callee.object, scopes))) return true;
|
|
51806
|
+
return false;
|
|
51677
51807
|
};
|
|
51678
51808
|
const containsImpureExpression = (expression, scopes) => {
|
|
51679
51809
|
let foundImpure = false;
|
|
@@ -56442,16 +56572,6 @@ const rnListCallbackPerRow = defineRule({
|
|
|
56442
56572
|
}
|
|
56443
56573
|
});
|
|
56444
56574
|
//#endregion
|
|
56445
|
-
//#region src/plugin/utils/get-require-call-source.ts
|
|
56446
|
-
const getRequireCallSource = (expression) => {
|
|
56447
|
-
if (isNodeOfType(expression, "MemberExpression")) return getRequireCallSource(expression.object);
|
|
56448
|
-
if (!isNodeOfType(expression, "CallExpression")) return null;
|
|
56449
|
-
if (!isNodeOfType(expression.callee, "Identifier") || expression.callee.name !== "require") return null;
|
|
56450
|
-
const [firstArgument] = expression.arguments ?? [];
|
|
56451
|
-
if (!firstArgument || !isNodeOfType(firstArgument, "Literal")) return null;
|
|
56452
|
-
return typeof firstArgument.value === "string" ? firstArgument.value : null;
|
|
56453
|
-
};
|
|
56454
|
-
//#endregion
|
|
56455
56575
|
//#region src/plugin/utils/get-initializer-module-source.ts
|
|
56456
56576
|
const getInitializerModuleSource = (contextNode, initializer) => {
|
|
56457
56577
|
const requireSource = getRequireCallSource(initializer);
|