eslint-plugin-react-x 5.14.5 → 5.14.7
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 +34 -75
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -144,7 +144,7 @@ const rules$6 = {
|
|
|
144
144
|
//#endregion
|
|
145
145
|
//#region package.json
|
|
146
146
|
var name$6 = "eslint-plugin-react-x";
|
|
147
|
-
var version = "5.14.
|
|
147
|
+
var version = "5.14.7";
|
|
148
148
|
|
|
149
149
|
//#endregion
|
|
150
150
|
//#region src/utils/create-rule.ts
|
|
@@ -1345,102 +1345,60 @@ const MUTATING_METHODS = /* @__PURE__ */ new Set([
|
|
|
1345
1345
|
"unshift"
|
|
1346
1346
|
]);
|
|
1347
1347
|
/**
|
|
1348
|
-
*
|
|
1349
|
-
* @param inner The node that may be contained.
|
|
1350
|
-
* @param outer The node that may contain it.
|
|
1351
|
-
*/
|
|
1352
|
-
function isNodeWithin(inner, outer) {
|
|
1353
|
-
return inner.range[0] >= outer.range[0] && inner.range[1] <= outer.range[1];
|
|
1354
|
-
}
|
|
1355
|
-
/**
|
|
1356
|
-
* Resolve an expression to the function it ultimately refers to, following
|
|
1357
|
-
* simple local aliasing (`const fn2 = fn;`) via scope resolution.
|
|
1358
|
-
* @param context The ESLint rule context.
|
|
1359
|
-
* @param node The expression to resolve.
|
|
1360
|
-
* @param seen Identifiers already visited, to guard against cycles.
|
|
1348
|
+
* Known navigation hooks.
|
|
1361
1349
|
*/
|
|
1350
|
+
const NAVIGATION_HOOKS = /* @__PURE__ */ new Set([
|
|
1351
|
+
"useNavigate",
|
|
1352
|
+
"useNavigation",
|
|
1353
|
+
"useRouter"
|
|
1354
|
+
]);
|
|
1362
1355
|
function resolveToFunctionNode(context, node, seen = /* @__PURE__ */ new Set()) {
|
|
1363
1356
|
const expr = Extract.unwrap(node);
|
|
1364
1357
|
if (Check.isFunction(expr)) return expr;
|
|
1365
|
-
if (expr.type !== AST_NODE_TYPES.Identifier) return null;
|
|
1366
|
-
if (seen.has(expr)) return null;
|
|
1358
|
+
if (expr.type !== AST_NODE_TYPES.Identifier || seen.has(expr)) return null;
|
|
1367
1359
|
seen.add(expr);
|
|
1368
1360
|
const resolved = resolve(context, expr);
|
|
1369
|
-
|
|
1370
|
-
return resolveToFunctionNode(context, resolved, seen);
|
|
1361
|
+
return resolved == null ? null : resolveToFunctionNode(context, resolved, seen);
|
|
1371
1362
|
}
|
|
1372
|
-
/**
|
|
1373
|
-
* Follow identifier-only variable-declarator aliases to their originating
|
|
1374
|
-
* binding. Assignment aliases are intentionally left for the value-flow phase.
|
|
1375
|
-
* @param context The ESLint rule context.
|
|
1376
|
-
* @param variable The binding whose initializer aliases should be followed.
|
|
1377
|
-
* @param seen Bindings already visited, to guard against cycles.
|
|
1378
|
-
*/
|
|
1379
1363
|
function resolveVariableOrigin(context, variable, seen = /* @__PURE__ */ new Set()) {
|
|
1380
1364
|
if (seen.has(variable)) return variable;
|
|
1381
1365
|
seen.add(variable);
|
|
1382
|
-
const
|
|
1383
|
-
if (
|
|
1384
|
-
const
|
|
1385
|
-
if (
|
|
1386
|
-
const source = findVariable(context.sourceCode.getScope(
|
|
1387
|
-
|
|
1388
|
-
return resolveVariableOrigin(context, source, seen);
|
|
1366
|
+
const def = variable.defs.length === 1 ? variable.defs[0] : null;
|
|
1367
|
+
if (def?.type !== DefinitionType.Variable || def.node.init == null) return variable;
|
|
1368
|
+
const init = Extract.unwrap(def.node.init);
|
|
1369
|
+
if (init.type !== AST_NODE_TYPES.Identifier) return variable;
|
|
1370
|
+
const source = findVariable(context.sourceCode.getScope(init), init);
|
|
1371
|
+
return source == null ? variable : resolveVariableOrigin(context, source, seen);
|
|
1389
1372
|
}
|
|
1390
|
-
/**
|
|
1391
|
-
* Check if a name is ref-like ("ref" or ends with "Ref").
|
|
1392
|
-
* Refs are mutable by design and exempted from immutability checks.
|
|
1393
|
-
* @param name The identifier name to check.
|
|
1394
|
-
*/
|
|
1395
1373
|
function isRefLikeName$1(name) {
|
|
1396
1374
|
return name === "ref" || name.endsWith("Ref");
|
|
1397
1375
|
}
|
|
1398
|
-
/**
|
|
1399
|
-
* Check if any identifier or property name in a member-expression chain
|
|
1400
|
-
* is ref-like.
|
|
1401
|
-
* @param node The AST node to inspect.
|
|
1402
|
-
*/
|
|
1403
1376
|
function hasRefLikeNameInChain(node) {
|
|
1404
1377
|
if (node.type === AST_NODE_TYPES.Identifier) return isRefLikeName$1(node.name);
|
|
1405
|
-
if (node.type
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
return hasRefLikeNameInChain(node.object);
|
|
1409
|
-
}
|
|
1410
|
-
return false;
|
|
1378
|
+
if (node.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
1379
|
+
const propertyName = Extract.getPropertyName(node.property);
|
|
1380
|
+
return propertyName != null ? isRefLikeName$1(propertyName) || hasRefLikeNameInChain(node.object) : hasRefLikeNameInChain(node.object);
|
|
1411
1381
|
}
|
|
1412
|
-
|
|
1413
|
-
* Check if the root identifier of a member-expression chain is initialized
|
|
1414
|
-
* from a `useRef()` call, following variable-declarator aliases.
|
|
1415
|
-
* @param context The ESLint rule context.
|
|
1416
|
-
* @param node The AST node to inspect (an identifier or member-expression chain).
|
|
1417
|
-
*/
|
|
1418
|
-
function isInitializedFromUseRef(context, node) {
|
|
1382
|
+
function isInitializedFromCall(context, node, isCall) {
|
|
1419
1383
|
const root = node.type === AST_NODE_TYPES.Identifier ? node : Extract.getRootIdentifier(node);
|
|
1420
1384
|
if (root == null) return false;
|
|
1421
1385
|
const variable = findVariable(context.sourceCode.getScope(root), root);
|
|
1422
1386
|
if (variable == null) return false;
|
|
1423
|
-
|
|
1387
|
+
const origin = resolveVariableOrigin(context, variable);
|
|
1388
|
+
const def = origin.defs.length === 1 ? origin.defs[0] : null;
|
|
1389
|
+
if (def?.type !== DefinitionType.Variable || def.node.init == null) return false;
|
|
1390
|
+
const init = Extract.unwrap(def.node.init);
|
|
1391
|
+
return init.type === AST_NODE_TYPES.CallExpression && isCall(init);
|
|
1424
1392
|
}
|
|
1425
|
-
function
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
const source = findVariable(context.sourceCode.getScope(initializer), initializer);
|
|
1434
|
-
return source != null && isVariableInitializedFromUseRef(context, source, seen);
|
|
1393
|
+
function isInitializedFromUseRef(context, node) {
|
|
1394
|
+
return isInitializedFromCall(context, node, (init) => core.isUseRefCall(context, init));
|
|
1395
|
+
}
|
|
1396
|
+
function isKnownNonMutatingMethodCall(context, node) {
|
|
1397
|
+
const callee = Extract.unwrap(node.callee);
|
|
1398
|
+
return Check.isExpression(callee) && isInitializedFromCall(context, callee, (init) => {
|
|
1399
|
+
return NAVIGATION_HOOKS.values().some((hook) => core.isAPICall(hook)(context, init));
|
|
1400
|
+
});
|
|
1435
1401
|
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Check if a mutated expression chain should be exempt from immutability
|
|
1438
|
-
* checks because it is rooted at a ref: either by naming convention
|
|
1439
|
-
* ({@link hasRefLikeNameInChain}) or because it is initialized from a
|
|
1440
|
-
* `useRef()` call ({@link isInitializedFromUseRef}).
|
|
1441
|
-
* @param context The ESLint rule context.
|
|
1442
|
-
* @param node The AST node to inspect (an identifier or member-expression chain).
|
|
1443
|
-
*/
|
|
1444
1402
|
function isRefLikeChain(context, node) {
|
|
1445
1403
|
return hasRefLikeNameInChain(node) || isInitializedFromUseRef(context, node);
|
|
1446
1404
|
}
|
|
@@ -1542,6 +1500,7 @@ function isRefMutation(context, mutation) {
|
|
|
1542
1500
|
function inferMutableFunctions(context, mutations) {
|
|
1543
1501
|
const mutableFunctions = /* @__PURE__ */ new Map();
|
|
1544
1502
|
for (const mutation of mutations) {
|
|
1503
|
+
if (mutation.node.type === AST_NODE_TYPES.CallExpression && isKnownNonMutatingMethodCall(context, mutation.node)) continue;
|
|
1545
1504
|
if (isRefMutation(context, mutation)) continue;
|
|
1546
1505
|
const variable = findVariable(context.sourceCode.getScope(mutation.root), mutation.root);
|
|
1547
1506
|
if (variable == null) continue;
|
|
@@ -1550,7 +1509,7 @@ function inferMutableFunctions(context, mutations) {
|
|
|
1550
1509
|
const declaration = origin.identifiers.at(0) ?? null;
|
|
1551
1510
|
let current = mutation.enclosingFunction;
|
|
1552
1511
|
while (current != null) {
|
|
1553
|
-
if (declaration != null &&
|
|
1512
|
+
if (declaration != null && Traverse.findParent(declaration, Check.isFunction) === current) break;
|
|
1554
1513
|
if (!mutableFunctions.has(current)) mutableFunctions.set(current, {
|
|
1555
1514
|
name: origin.name,
|
|
1556
1515
|
node: mutation.node
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "5.14.
|
|
3
|
+
"version": "5.14.7",
|
|
4
4
|
"description": "A set of composable ESLint rules for libraries and frameworks that use React as a UI runtime.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -45,26 +45,26 @@
|
|
|
45
45
|
"string-ts": "^2.3.1",
|
|
46
46
|
"ts-api-utils": "^2.5.0",
|
|
47
47
|
"ts-pattern": "^5.9.0",
|
|
48
|
-
"@eslint-react/
|
|
49
|
-
"@eslint-react/
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/jsx": "5.14.
|
|
52
|
-
"@eslint-react/
|
|
53
|
-
"@eslint-react/
|
|
48
|
+
"@eslint-react/ast": "5.14.7",
|
|
49
|
+
"@eslint-react/core": "5.14.7",
|
|
50
|
+
"@eslint-react/eslint": "5.14.7",
|
|
51
|
+
"@eslint-react/jsx": "5.14.7",
|
|
52
|
+
"@eslint-react/var": "5.14.7",
|
|
53
|
+
"@eslint-react/shared": "5.14.7"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/react": "^19.2.17",
|
|
57
57
|
"@types/react-dom": "^19.2.3",
|
|
58
58
|
"dedent": "^1.7.2",
|
|
59
|
-
"eslint": "^10.
|
|
59
|
+
"eslint": "^10.7.0",
|
|
60
60
|
"react": "^19.2.7",
|
|
61
61
|
"react-dom": "^19.2.7",
|
|
62
62
|
"tsdown": "^0.22.4",
|
|
63
63
|
"tsl": "^1.0.30",
|
|
64
64
|
"tsl-dx": "^0.13.2",
|
|
65
65
|
"typescript": "6.0.3",
|
|
66
|
-
"@local/
|
|
67
|
-
"@local/
|
|
66
|
+
"@local/configs": "0.0.0",
|
|
67
|
+
"@local/eff": "0.0.0"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"eslint": "*",
|