eslint-plugin-react-x 5.18.2 → 5.18.4
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 +134 -124
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -145,7 +145,7 @@ const rules$6 = {
|
|
|
145
145
|
//#endregion
|
|
146
146
|
//#region package.json
|
|
147
147
|
var name$6 = "eslint-plugin-react-x";
|
|
148
|
-
var version = "5.18.
|
|
148
|
+
var version = "5.18.4";
|
|
149
149
|
|
|
150
150
|
//#endregion
|
|
151
151
|
//#region src/utils/create-rule.ts
|
|
@@ -531,15 +531,16 @@ const rule$1 = {
|
|
|
531
531
|
declaredDependency = analyzePropertyChain(declaredDependencyNode, null);
|
|
532
532
|
} catch (error) {
|
|
533
533
|
if (error instanceof Error && /Unsupported node type/.test(error.message)) {
|
|
534
|
-
if (declaredDependencyNode.type === "Literal")
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
534
|
+
if (declaredDependencyNode.type === "Literal") {
|
|
535
|
+
if (declaredDependencyNode.value && dependencies.has(declaredDependencyNode.value)) reportProblem({
|
|
536
|
+
node: declaredDependencyNode,
|
|
537
|
+
message: `The ${declaredDependencyNode.raw} literal is not a valid dependency because it never changes. Did you mean to include ${declaredDependencyNode.value} in the array instead?`
|
|
538
|
+
});
|
|
539
|
+
else reportProblem({
|
|
540
|
+
node: declaredDependencyNode,
|
|
541
|
+
message: `The ${declaredDependencyNode.raw} literal is not a valid dependency because it never changes. You can safely remove it.`
|
|
542
|
+
});
|
|
543
|
+
} else reportProblem({
|
|
543
544
|
node: declaredDependencyNode,
|
|
544
545
|
message: `React Hook ${getSourceCode().getText(reactiveHook)} has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked.`
|
|
545
546
|
});
|
|
@@ -813,7 +814,6 @@ const rule$1 = {
|
|
|
813
814
|
visitFunctionWithDependencies(init, declaredDependenciesNode, reactiveHook, reactiveHookName, isEffect, isAutoDepsHook);
|
|
814
815
|
return;
|
|
815
816
|
}
|
|
816
|
-
break;
|
|
817
817
|
}
|
|
818
818
|
break;
|
|
819
819
|
default:
|
|
@@ -906,9 +906,10 @@ function collectRecommendations({ dependencies, declaredDependencies, stableDepe
|
|
|
906
906
|
const unnecessaryDependencies = /* @__PURE__ */ new Set();
|
|
907
907
|
const duplicateDependencies = /* @__PURE__ */ new Set();
|
|
908
908
|
declaredDependencies.forEach(({ key }) => {
|
|
909
|
-
if (satisfyingDependencies.has(key))
|
|
910
|
-
|
|
911
|
-
|
|
909
|
+
if (satisfyingDependencies.has(key)) {
|
|
910
|
+
if (suggestedDependencies.indexOf(key) === -1) suggestedDependencies.push(key);
|
|
911
|
+
else duplicateDependencies.add(key);
|
|
912
|
+
} else if (isEffect && !key.endsWith(".current") && !externalDependencies.has(key)) {
|
|
912
913
|
if (suggestedDependencies.indexOf(key) === -1) suggestedDependencies.push(key);
|
|
913
914
|
} else unnecessaryDependencies.add(key);
|
|
914
915
|
});
|
|
@@ -967,10 +968,12 @@ function scanForConstructions({ declaredDependencies, declaredDependenciesNode,
|
|
|
967
968
|
function isUsedOutsideOfHook(ref) {
|
|
968
969
|
let foundWriteExpr = false;
|
|
969
970
|
for (const reference of ref.references) {
|
|
970
|
-
if (reference.writeExpr)
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
971
|
+
if (reference.writeExpr) {
|
|
972
|
+
if (foundWriteExpr) return true;
|
|
973
|
+
else {
|
|
974
|
+
foundWriteExpr = true;
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
974
977
|
}
|
|
975
978
|
let currentScope = reference.from;
|
|
976
979
|
while (currentScope !== scope && currentScope != null) currentScope = currentScope.upper;
|
|
@@ -1005,9 +1008,11 @@ function getDependency(node) {
|
|
|
1005
1008
|
* This particular node might still represent a required member, so check .optional field.
|
|
1006
1009
|
*/
|
|
1007
1010
|
function markNode(node, optionalChains, result) {
|
|
1008
|
-
if (optionalChains)
|
|
1009
|
-
if (
|
|
1010
|
-
|
|
1011
|
+
if (optionalChains) {
|
|
1012
|
+
if ("optional" in node && node.optional) {
|
|
1013
|
+
if (!optionalChains.has(result)) optionalChains.set(result, true);
|
|
1014
|
+
} else optionalChains.set(result, false);
|
|
1015
|
+
}
|
|
1011
1016
|
}
|
|
1012
1017
|
/**
|
|
1013
1018
|
* Assuming () means the passed node.
|
|
@@ -1916,10 +1921,12 @@ function create$40(context) {
|
|
|
1916
1921
|
if (!context.sourceCode.text.includes("Component")) return {};
|
|
1917
1922
|
const { api, visitor } = core.getClassComponentCollector(context);
|
|
1918
1923
|
return merge(visitor, { "Program:exit"(program) {
|
|
1919
|
-
for (const { name = "anonymous", node: component } of api.getAllComponents(program)) {
|
|
1924
|
+
for (const { id, name = "anonymous", node: component } of api.getAllComponents(program)) {
|
|
1920
1925
|
if (component.body.body.some((m) => core.isComponentDidCatch(m) || core.isGetDerivedStateFromError(m))) continue;
|
|
1926
|
+
const classToken = context.sourceCode.getFirstToken(component, { filter: (token) => token.value === "class" });
|
|
1921
1927
|
context.report({
|
|
1922
1928
|
data: { name },
|
|
1929
|
+
loc: (id ?? classToken ?? component).loc,
|
|
1923
1930
|
messageId: "default",
|
|
1924
1931
|
node: component
|
|
1925
1932
|
});
|
|
@@ -3396,47 +3403,39 @@ function create$23(context) {
|
|
|
3396
3403
|
|
|
3397
3404
|
//#endregion
|
|
3398
3405
|
//#region src/rules/no-nested-component-definitions/lib.ts
|
|
3406
|
+
/** Check if the node is a call expression to react-redux's `connect`. */
|
|
3407
|
+
const isConnectCall = core.isAPICall("connect");
|
|
3408
|
+
/** Check if the node is a call expression to Relay's `createFragmentContainer`. */
|
|
3409
|
+
const isCreateFragmentContainerCall = core.isAPICall("createFragmentContainer");
|
|
3410
|
+
/** Check if the node is a call expression to Relay's `createPaginationContainer`. */
|
|
3411
|
+
const isCreatePaginationContainerCall = core.isAPICall("createPaginationContainer");
|
|
3412
|
+
/** Check if the node is a call expression to Relay's `createRefetchContainer`. */
|
|
3413
|
+
const isCreateRefetchContainerCall = core.isAPICall("createRefetchContainer");
|
|
3414
|
+
/** Check if the node is a call expression to React's `forwardRef`. */
|
|
3415
|
+
const isForwardRefCall = core.isAPICall("forwardRef");
|
|
3416
|
+
/** Check if the node is a call expression to a `graphql` tag function (e.g. from Relay or Apollo). */
|
|
3417
|
+
const isGraphqlCall = core.isAPICall("graphql");
|
|
3418
|
+
/** Check if the node is a call expression to React's `memo`. */
|
|
3419
|
+
const isMemoCall = core.isAPICall("memo");
|
|
3420
|
+
/** Check if the node is a call expression to MobX's `observer`. */
|
|
3421
|
+
const isObserverCall = core.isAPICall("observer");
|
|
3422
|
+
/** Check if the node is a call expression to React's `useCallback`. */
|
|
3423
|
+
const isUseCallbackCall = core.isAPICall("useCallback");
|
|
3424
|
+
/** Check if the node is a call expression to Formik's `withFormik`. */
|
|
3425
|
+
const isWithFormikCall = core.isAPICall("withFormik");
|
|
3426
|
+
/** Check if the node is a call expression to recompose's `withHandlers`. */
|
|
3427
|
+
const isWithHandlersCall = core.isAPICall("withHandlers");
|
|
3428
|
+
/** Check if the node is a call expression to recompose's `withLifecycle`. */
|
|
3429
|
+
const isWithLifecycleCall = core.isAPICall("withLifecycle");
|
|
3430
|
+
/** Check if the node is a call expression to recompose's `withProps`. */
|
|
3431
|
+
const isWithPropsCall = core.isAPICall("withProps");
|
|
3432
|
+
/** Check if the node is a call expression to react-router v5's `withRouter`. */
|
|
3433
|
+
const isWithRouterCall = core.isAPICall("withRouter");
|
|
3434
|
+
/** Check if the node is a call expression to recompose's `withState`. */
|
|
3435
|
+
const isWithStateCall = core.isAPICall("withState");
|
|
3399
3436
|
/**
|
|
3400
|
-
*
|
|
3401
|
-
*
|
|
3402
|
-
* or Relay's `create*Container` helpers). Only wrappers whose argument is a render function
|
|
3403
|
-
* are listed; wrappers taking a component identifier (`styled`, `motion`) or a loader
|
|
3404
|
-
* (`lazy`, `dynamic`) are irrelevant for name resolution.
|
|
3405
|
-
*/
|
|
3406
|
-
const WELL_KNOWN_COMPONENT_WRAPPERS = [
|
|
3407
|
-
"connect",
|
|
3408
|
-
"createFragmentContainer",
|
|
3409
|
-
"createPaginationContainer",
|
|
3410
|
-
"createRefetchContainer",
|
|
3411
|
-
"forwardRef",
|
|
3412
|
-
"graphql",
|
|
3413
|
-
"memo",
|
|
3414
|
-
"observer",
|
|
3415
|
-
"useCallback"
|
|
3416
|
-
];
|
|
3417
|
-
/** Matches the HOC naming convention shared by recompose, react-router v5, Formik and custom HOCs (e.g. `withProps`, `withRouter`, `withFormik`, `withAuth`). */
|
|
3418
|
-
const RE_HOC_WRAPPER_NAME = /^with[A-Z]/;
|
|
3419
|
-
/**
|
|
3420
|
-
* Check if a call expression is a well-known component wrapper call.
|
|
3421
|
-
* Only calls whose callee's fully qualified name is (or ends with) a well-known wrapper
|
|
3422
|
-
* name (e.g. `memo`, `React.memo`, `React.useCallback`, `mobx.observer`) are treated as
|
|
3423
|
-
* wrappers; anything else, including member calls on data objects (e.g. `items.map`,
|
|
3424
|
-
* `Array.from`), is not, so array method callbacks are never mistaken for wrapped components.
|
|
3425
|
-
* Curried wrappers like `connect(...)(Component)` or `withFormik(...)(Component)` are
|
|
3426
|
-
* recognized by unwrapping nested callee call expressions.
|
|
3427
|
-
* @param context The rule context
|
|
3428
|
-
* @param node The call expression to check
|
|
3429
|
-
* @returns `true` if the call is a well-known component wrapper call
|
|
3430
|
-
*/
|
|
3431
|
-
function isWellKnownComponentWrapperCall(context, node) {
|
|
3432
|
-
let callee = Extract.unwrap(node.callee);
|
|
3433
|
-
while (callee.type === AST_NODE_TYPES.CallExpression) callee = Extract.unwrap(callee.callee);
|
|
3434
|
-
const name = Extract.getFullyQualifiedName(callee, (n) => context.sourceCode.getText(n));
|
|
3435
|
-
const baseName = name.slice(name.lastIndexOf(".") + 1);
|
|
3436
|
-
return RE_HOC_WRAPPER_NAME.test(baseName) || WELL_KNOWN_COMPONENT_WRAPPERS.some((wrapper) => name === wrapper || name.endsWith(`.${wrapper}`));
|
|
3437
|
-
}
|
|
3438
|
-
/**
|
|
3439
|
-
* Check if a call expression is a component wrapper call for name resolution purposes.
|
|
3437
|
+
* Check if a call is a well-known component wrapper call (e.g. `memo`, `connect`, `withFormik`).
|
|
3438
|
+
* Curried forms like `connect(...)(Component)` are matched via the innermost callee call.
|
|
3440
3439
|
* @param context The rule context
|
|
3441
3440
|
* @param call The call expression to check
|
|
3442
3441
|
* @param arg The function node passed to the call
|
|
@@ -3444,14 +3443,29 @@ function isWellKnownComponentWrapperCall(context, node) {
|
|
|
3444
3443
|
*/
|
|
3445
3444
|
function isComponentWrapperCall(context, call, arg) {
|
|
3446
3445
|
if (Extract.unwrap(call.callee) === arg) return false;
|
|
3447
|
-
|
|
3446
|
+
call = Extract.getInnermostCall(call);
|
|
3447
|
+
if (isConnectCall(context, call)) return true;
|
|
3448
|
+
if (isCreateFragmentContainerCall(context, call)) return true;
|
|
3449
|
+
if (isCreatePaginationContainerCall(context, call)) return true;
|
|
3450
|
+
if (isCreateRefetchContainerCall(context, call)) return true;
|
|
3451
|
+
if (isForwardRefCall(context, call)) return true;
|
|
3452
|
+
if (isGraphqlCall(context, call)) return true;
|
|
3453
|
+
if (isMemoCall(context, call)) return true;
|
|
3454
|
+
if (isObserverCall(context, call)) return true;
|
|
3455
|
+
if (isUseCallbackCall(context, call)) return true;
|
|
3456
|
+
if (isWithFormikCall(context, call)) return true;
|
|
3457
|
+
if (isWithHandlersCall(context, call)) return true;
|
|
3458
|
+
if (isWithLifecycleCall(context, call)) return true;
|
|
3459
|
+
if (isWithPropsCall(context, call)) return true;
|
|
3460
|
+
if (isWithRouterCall(context, call)) return true;
|
|
3461
|
+
if (isWithStateCall(context, call)) return true;
|
|
3462
|
+
return false;
|
|
3448
3463
|
}
|
|
3449
3464
|
/**
|
|
3450
|
-
* Resolve the name a function is bound to through
|
|
3451
|
-
* e.g. `const Component = useCallback(() => <div />, [])` resolves to `Component`.
|
|
3465
|
+
* Resolve the name a function is bound to through wrapping calls (e.g. `const C = useCallback(...)` → `C`).
|
|
3452
3466
|
* @param context The rule context
|
|
3453
3467
|
* @param node The function node to resolve the bound name for
|
|
3454
|
-
* @returns The bound name if the call chain
|
|
3468
|
+
* @returns The bound name, or `null` if the call chain does not end at an identifier declarator
|
|
3455
3469
|
*/
|
|
3456
3470
|
function getWrapperCallBoundName(context, node) {
|
|
3457
3471
|
let current = node;
|
|
@@ -3472,7 +3486,7 @@ function getWrapperCallBoundName(context, node) {
|
|
|
3472
3486
|
return parent.id.name;
|
|
3473
3487
|
}
|
|
3474
3488
|
/**
|
|
3475
|
-
*
|
|
3489
|
+
* Check if the node is inside `createElement`'s props argument
|
|
3476
3490
|
* @param context The rule context
|
|
3477
3491
|
* @param node The AST node to check
|
|
3478
3492
|
* @returns `true` if the node is inside `createElement`'s props
|
|
@@ -3485,17 +3499,17 @@ function isInsideCreateElementProps(context, node) {
|
|
|
3485
3499
|
return prop === call.arguments[1];
|
|
3486
3500
|
}
|
|
3487
3501
|
/**
|
|
3488
|
-
*
|
|
3502
|
+
* Check if the node is inside a JSX attribute value
|
|
3489
3503
|
* @param node The AST node to check
|
|
3490
|
-
* @returns `true` if the node is inside JSX attribute value
|
|
3504
|
+
* @returns `true` if the node is inside a JSX attribute value
|
|
3491
3505
|
*/
|
|
3492
3506
|
function isInsideJSXAttributeValue(node) {
|
|
3493
3507
|
return node.parent.type === AST_NODE_TYPES.JSXAttribute || findParentAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
|
|
3494
3508
|
}
|
|
3495
3509
|
/**
|
|
3496
|
-
* Check
|
|
3510
|
+
* Check if the node is declared inside a class component's render block
|
|
3497
3511
|
* Ex: class C extends React.Component { render() { const Nested = () => <div />; } }
|
|
3498
|
-
* @param node The AST node
|
|
3512
|
+
* @param node The AST node to check
|
|
3499
3513
|
* @returns `true` if the node is inside a class component's render block
|
|
3500
3514
|
*/
|
|
3501
3515
|
function isInsideRenderMethod(node) {
|
|
@@ -4077,7 +4091,9 @@ function create$11(context) {
|
|
|
4077
4091
|
for (const def of defs) {
|
|
4078
4092
|
const methodName = def.name;
|
|
4079
4093
|
if (usages?.has(methodName) ?? false) continue;
|
|
4080
|
-
if (LIFECYCLE_METHODS.has(methodName))
|
|
4094
|
+
if (LIFECYCLE_METHODS.has(methodName)) {
|
|
4095
|
+
if (methodName === "shouldComponentUpdate" && core.isPureComponent(currentClass)) {} else continue;
|
|
4096
|
+
}
|
|
4081
4097
|
context.report({
|
|
4082
4098
|
data: {
|
|
4083
4099
|
className: id != null ? context.sourceCode.getText(id) : "Component",
|
|
@@ -4148,9 +4164,7 @@ function collectUsedPropKeysOfObjectPattern(context, usedPropKeys, objectPattern
|
|
|
4148
4164
|
usedPropKeys.add(key);
|
|
4149
4165
|
break;
|
|
4150
4166
|
}
|
|
4151
|
-
case AST_NODE_TYPES.RestElement:
|
|
4152
|
-
if (!collectUsedPropsOfRestElement(context, usedPropKeys, property)) return false;
|
|
4153
|
-
break;
|
|
4167
|
+
case AST_NODE_TYPES.RestElement: if (!collectUsedPropsOfRestElement(context, usedPropKeys, property)) return false;
|
|
4154
4168
|
}
|
|
4155
4169
|
return true;
|
|
4156
4170
|
}
|
|
@@ -4182,18 +4196,14 @@ function collectUsedPropKeysOfReference(context, usedPropKeys, ref) {
|
|
|
4182
4196
|
return true;
|
|
4183
4197
|
}
|
|
4184
4198
|
break;
|
|
4185
|
-
case AST_NODE_TYPES.VariableDeclarator:
|
|
4186
|
-
if (parent.id.type === AST_NODE_TYPES.ObjectPattern && parent.init === valueNode) return collectUsedPropKeysOfObjectPattern(context, usedPropKeys, parent.id);
|
|
4187
|
-
break;
|
|
4199
|
+
case AST_NODE_TYPES.VariableDeclarator: if (parent.id.type === AST_NODE_TYPES.ObjectPattern && parent.init === valueNode) return collectUsedPropKeysOfObjectPattern(context, usedPropKeys, parent.id);
|
|
4188
4200
|
}
|
|
4189
4201
|
return false;
|
|
4190
4202
|
}
|
|
4191
4203
|
function getKeyOfExpression(expr) {
|
|
4192
4204
|
switch (expr.type) {
|
|
4193
4205
|
case AST_NODE_TYPES.Identifier: return expr.name;
|
|
4194
|
-
case AST_NODE_TYPES.Literal:
|
|
4195
|
-
if (typeof expr.value === "string") return expr.value;
|
|
4196
|
-
break;
|
|
4206
|
+
case AST_NODE_TYPES.Literal: if (typeof expr.value === "string") return expr.value;
|
|
4197
4207
|
}
|
|
4198
4208
|
return null;
|
|
4199
4209
|
}
|
|
@@ -4280,7 +4290,8 @@ function create$9(context) {
|
|
|
4280
4290
|
},
|
|
4281
4291
|
"Program:exit"() {
|
|
4282
4292
|
for (const { name, node } of stateEntries) {
|
|
4283
|
-
const
|
|
4293
|
+
const scope = context.sourceCode.getScope(node);
|
|
4294
|
+
const variable = findVariable(scope, name);
|
|
4284
4295
|
if (variable == null) continue;
|
|
4285
4296
|
let hasRead = false;
|
|
4286
4297
|
for (const ref of variable.references) {
|
|
@@ -4636,7 +4647,8 @@ const IMPURE_CTORS = /* @__PURE__ */ new Set([
|
|
|
4636
4647
|
function resolveBuiltinObjectName(context, node, seen = /* @__PURE__ */ new Set()) {
|
|
4637
4648
|
if (seen.has(node.name)) return null;
|
|
4638
4649
|
seen.add(node.name);
|
|
4639
|
-
const
|
|
4650
|
+
const scope = context.sourceCode.getScope(node);
|
|
4651
|
+
const variable = findVariable(scope, node);
|
|
4640
4652
|
if (variable == null) return node.name;
|
|
4641
4653
|
const def = variable.defs[0];
|
|
4642
4654
|
if (def == null) return node.name;
|
|
@@ -5853,10 +5865,12 @@ var CodePathState = class {
|
|
|
5853
5865
|
this.forkBypassPath();
|
|
5854
5866
|
const lastCaseSegments = forkContext.head;
|
|
5855
5867
|
brokenForkContext.add(lastSegments);
|
|
5856
|
-
if (!context.lastIsDefault)
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5868
|
+
if (!context.lastIsDefault) {
|
|
5869
|
+
if (context.defaultBodySegments) {
|
|
5870
|
+
removeConnection(context.defaultSegments, context.defaultBodySegments);
|
|
5871
|
+
makeLooped(this, lastCaseSegments, context.defaultBodySegments);
|
|
5872
|
+
} else brokenForkContext.add(lastCaseSegments);
|
|
5873
|
+
}
|
|
5860
5874
|
for (let i = 0; i < context.countForks; ++i) this.forkContext = this.forkContext.upper;
|
|
5861
5875
|
this.forkContext.replaceHead(brokenForkContext.makeNext(0, -1));
|
|
5862
5876
|
}
|
|
@@ -6258,10 +6272,12 @@ var CodePathState = class {
|
|
|
6258
6272
|
const forkContext = this.forkContext;
|
|
6259
6273
|
if (!forkContext.reachable) return;
|
|
6260
6274
|
const context = getContinueContext(this, label);
|
|
6261
|
-
if (context)
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6275
|
+
if (context) {
|
|
6276
|
+
if (context.continueDestSegments != null) {
|
|
6277
|
+
makeLooped(this, forkContext.head, context.continueDestSegments);
|
|
6278
|
+
if (context.type === "ForInStatement" || context.type === "ForOfStatement") context.brokenForkContext.add(forkContext.head);
|
|
6279
|
+
} else context.continueForkContext.add(forkContext.head);
|
|
6280
|
+
}
|
|
6265
6281
|
forkContext.replaceHead(forkContext.makeUnreachable(-1, -1));
|
|
6266
6282
|
}
|
|
6267
6283
|
/**
|
|
@@ -6656,14 +6672,11 @@ function preprocess(analyzer, node) {
|
|
|
6656
6672
|
state.makeForInOfBody();
|
|
6657
6673
|
}
|
|
6658
6674
|
break;
|
|
6659
|
-
case "AssignmentPattern":
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
}
|
|
6665
|
-
break;
|
|
6666
|
-
default: break;
|
|
6675
|
+
case "AssignmentPattern": if (parent.right === node) {
|
|
6676
|
+
state.pushForkContext();
|
|
6677
|
+
state.forkBypassPath();
|
|
6678
|
+
state.forkPath();
|
|
6679
|
+
}
|
|
6667
6680
|
}
|
|
6668
6681
|
}
|
|
6669
6682
|
/**
|
|
@@ -6738,10 +6751,7 @@ function processCodePathToEnter(analyzer, node) {
|
|
|
6738
6751
|
case "ForOfStatement":
|
|
6739
6752
|
state.pushLoopContext(node.type, getLabel(node));
|
|
6740
6753
|
break;
|
|
6741
|
-
case "LabeledStatement":
|
|
6742
|
-
if (!breakableTypePattern.test(node.body.type)) state.pushBreakContext(false, node.label.name);
|
|
6743
|
-
break;
|
|
6744
|
-
default: break;
|
|
6754
|
+
case "LabeledStatement": if (!breakableTypePattern.test(node.body.type)) state.pushBreakContext(false, node.label.name);
|
|
6745
6755
|
}
|
|
6746
6756
|
forwardCurrentToHead(analyzer, node);
|
|
6747
6757
|
}
|
|
@@ -6819,10 +6829,7 @@ function processCodePathToExit(analyzer, node) {
|
|
|
6819
6829
|
case "AssignmentPattern":
|
|
6820
6830
|
state.popForkContext();
|
|
6821
6831
|
break;
|
|
6822
|
-
case "LabeledStatement":
|
|
6823
|
-
if (!breakableTypePattern.test(node.body.type)) state.popBreakContext();
|
|
6824
|
-
break;
|
|
6825
|
-
default: break;
|
|
6832
|
+
case "LabeledStatement": if (!breakableTypePattern.test(node.body.type)) state.popBreakContext();
|
|
6826
6833
|
}
|
|
6827
6834
|
if (!dontForward) forwardCurrentToHead(analyzer, node);
|
|
6828
6835
|
}
|
|
@@ -6847,10 +6854,7 @@ function postprocess(analyzer, node) {
|
|
|
6847
6854
|
case "StaticBlock":
|
|
6848
6855
|
endCodePath();
|
|
6849
6856
|
break;
|
|
6850
|
-
case "CallExpression":
|
|
6851
|
-
if (node.optional === true && node.arguments.length === 0) CodePath.getState(analyzer.codePath).makeOptionalRight();
|
|
6852
|
-
break;
|
|
6853
|
-
default: break;
|
|
6857
|
+
case "CallExpression": if (node.optional === true && node.arguments.length === 0) CodePath.getState(analyzer.codePath).makeOptionalRight();
|
|
6854
6858
|
}
|
|
6855
6859
|
if (isPropertyDefinitionValue(node)) endCodePath();
|
|
6856
6860
|
}
|
|
@@ -7310,12 +7314,13 @@ const rule = {
|
|
|
7310
7314
|
*/
|
|
7311
7315
|
function getFunctionName(node) {
|
|
7312
7316
|
if (node.type === "ComponentDeclaration" || node.type === "HookDeclaration" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" && node.id) return node.id;
|
|
7313
|
-
else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression")
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
|
|
7317
|
+
else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
|
|
7318
|
+
if (node.parent?.type === "VariableDeclarator" && node.parent.init === node) return node.parent.id;
|
|
7319
|
+
else if (node.parent?.type === "AssignmentExpression" && node.parent.right === node && node.parent.operator === "=") return node.parent.left;
|
|
7320
|
+
else if (node.parent?.type === "Property" && node.parent.value === node && !node.parent.computed) return node.parent.key;
|
|
7321
|
+
else if (node.parent?.type === "AssignmentPattern" && node.parent.right === node && !node.parent.computed) return node.parent.left;
|
|
7322
|
+
else return;
|
|
7323
|
+
} else return;
|
|
7319
7324
|
}
|
|
7320
7325
|
/**
|
|
7321
7326
|
* Convenience function for peeking the last item in a stack.
|
|
@@ -7547,13 +7552,15 @@ function create$5(context) {
|
|
|
7547
7552
|
const isAt = Extract.getCalleeName(callee) === "at";
|
|
7548
7553
|
const [index] = callee.arguments;
|
|
7549
7554
|
if (!isAt || index == null) return false;
|
|
7550
|
-
|
|
7555
|
+
const indexScope = context.sourceCode.getScope(node);
|
|
7556
|
+
return getStaticValue(index, indexScope)?.value === 1 && isIdFromUseStateCall(innerCallee.object);
|
|
7551
7557
|
}
|
|
7552
7558
|
case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(callee, 1);
|
|
7553
7559
|
case AST_NODE_TYPES.MemberExpression: {
|
|
7554
7560
|
if (!("name" in callee.object)) return false;
|
|
7555
7561
|
const property = callee.property;
|
|
7556
|
-
|
|
7562
|
+
const propertyScope = context.sourceCode.getScope(node);
|
|
7563
|
+
return getStaticValue(property, propertyScope)?.value === 1 && isIdFromUseStateCall(callee.object, 1);
|
|
7557
7564
|
}
|
|
7558
7565
|
default: return false;
|
|
7559
7566
|
}
|
|
@@ -7706,7 +7713,6 @@ function isInsideConditional(node, stopAt) {
|
|
|
7706
7713
|
case AST_NODE_TYPES.LogicalExpression:
|
|
7707
7714
|
case AST_NODE_TYPES.SwitchStatement:
|
|
7708
7715
|
case AST_NODE_TYPES.SwitchCase: return true;
|
|
7709
|
-
default: break;
|
|
7710
7716
|
}
|
|
7711
7717
|
current = current.parent;
|
|
7712
7718
|
}
|
|
@@ -7769,13 +7775,15 @@ function create$4(context) {
|
|
|
7769
7775
|
const isAt = Extract.getCalleeName(callee) === "at";
|
|
7770
7776
|
const [index] = callee.arguments;
|
|
7771
7777
|
if (!isAt || index == null) return false;
|
|
7772
|
-
|
|
7778
|
+
const indexScope = context.sourceCode.getScope(node);
|
|
7779
|
+
return getStaticValue(index, indexScope)?.value === 1 && isIdFromUseStateCall(innerCallee.object);
|
|
7773
7780
|
}
|
|
7774
7781
|
case AST_NODE_TYPES.Identifier: return isIdFromUseStateCall(callee, 1);
|
|
7775
7782
|
case AST_NODE_TYPES.MemberExpression: {
|
|
7776
7783
|
if (!("name" in callee.object)) return false;
|
|
7777
7784
|
const property = callee.property;
|
|
7778
|
-
|
|
7785
|
+
const propertyScope = context.sourceCode.getScope(node);
|
|
7786
|
+
return getStaticValue(property, propertyScope)?.value === 1 && isIdFromUseStateCall(callee.object, 1);
|
|
7779
7787
|
}
|
|
7780
7788
|
default: return false;
|
|
7781
7789
|
}
|
|
@@ -7850,7 +7858,8 @@ const DYNAMIC_EXPRESSION_TYPES = /* @__PURE__ */ new Set([
|
|
|
7850
7858
|
AST_NODE_TYPES.NewExpression
|
|
7851
7859
|
]);
|
|
7852
7860
|
function findVariableForIdentifier(context, identifier) {
|
|
7853
|
-
|
|
7861
|
+
const scope = context.sourceCode.getScope(identifier);
|
|
7862
|
+
return findVariable(scope, identifier.name);
|
|
7854
7863
|
}
|
|
7855
7864
|
/**
|
|
7856
7865
|
* Resolves an expression down to the node that dynamically created its value, if any.
|
|
@@ -8114,7 +8123,8 @@ function create$1(context) {
|
|
|
8114
8123
|
const left = Extract.unwrap(node.left);
|
|
8115
8124
|
if (left.type !== AST_NODE_TYPES.Identifier) return;
|
|
8116
8125
|
if (Traverse.findParent(node, Check.isFunction, (n) => n === callback) != null) return;
|
|
8117
|
-
const
|
|
8126
|
+
const scope = context.sourceCode.getScope(left);
|
|
8127
|
+
const variable = findVariable(scope, left);
|
|
8118
8128
|
if (variable != null && variable.defs.length > 0 && isDeclaredInsideCallback(variable, callback)) return;
|
|
8119
8129
|
violations.push({
|
|
8120
8130
|
messageId: "noReassigningOuterVariables",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "5.18.
|
|
3
|
+
"version": "5.18.4",
|
|
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",
|
|
@@ -36,27 +36,27 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@typescript-eslint/scope-manager": "^8.
|
|
40
|
-
"@typescript-eslint/type-utils": "^8.
|
|
41
|
-
"@typescript-eslint/types": "^8.
|
|
42
|
-
"@typescript-eslint/typescript-estree": "^8.
|
|
43
|
-
"@typescript-eslint/utils": "^8.
|
|
39
|
+
"@typescript-eslint/scope-manager": "^8.66.0",
|
|
40
|
+
"@typescript-eslint/type-utils": "^8.66.0",
|
|
41
|
+
"@typescript-eslint/types": "^8.66.0",
|
|
42
|
+
"@typescript-eslint/typescript-estree": "^8.66.0",
|
|
43
|
+
"@typescript-eslint/utils": "^8.66.0",
|
|
44
44
|
"compare-versions": "^6.1.1",
|
|
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/ast": "5.18.
|
|
49
|
-
"@eslint-react/core": "5.18.
|
|
50
|
-
"@eslint-react/eslint": "5.18.
|
|
51
|
-
"@eslint-react/jsx": "5.18.
|
|
52
|
-
"@eslint-react/var": "5.18.
|
|
53
|
-
"@eslint-react/shared": "5.18.
|
|
48
|
+
"@eslint-react/ast": "5.18.4",
|
|
49
|
+
"@eslint-react/core": "5.18.4",
|
|
50
|
+
"@eslint-react/eslint": "5.18.4",
|
|
51
|
+
"@eslint-react/jsx": "5.18.4",
|
|
52
|
+
"@eslint-react/var": "5.18.4",
|
|
53
|
+
"@eslint-react/shared": "5.18.4"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/react": "^19.2.18",
|
|
57
57
|
"@types/react-dom": "^19.2.4",
|
|
58
58
|
"dedent": "^1.7.2",
|
|
59
|
-
"eslint": "^10.8.
|
|
59
|
+
"eslint": "^10.8.1",
|
|
60
60
|
"react": "^19.2.8",
|
|
61
61
|
"react-dom": "^19.2.8",
|
|
62
62
|
"tsdown": "^0.22.14",
|