eslint-plugin-react-x 5.5.2-beta.0 → 5.5.3-beta.0

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.
Files changed (2) hide show
  1. package/dist/index.js +97 -48
  2. package/package.json +9 -9
package/dist/index.js CHANGED
@@ -142,7 +142,7 @@ const rules$6 = {
142
142
  //#endregion
143
143
  //#region package.json
144
144
  var name$6 = "eslint-plugin-react-x";
145
- var version = "5.5.2-beta.0";
145
+ var version = "5.5.3-beta.0";
146
146
 
147
147
  //#endregion
148
148
  //#region src/utils/create-rule.ts
@@ -6932,6 +6932,83 @@ function create$4(context) {
6932
6932
  });
6933
6933
  }
6934
6934
 
6935
+ //#endregion
6936
+ //#region src/rules/static-components/lib.ts
6937
+ function resolveDynamicValue(context, node, isInsideRender, seen) {
6938
+ const expr = Extract.unwrap(node);
6939
+ switch (expr.type) {
6940
+ case AST_NODE_TYPES.FunctionExpression:
6941
+ case AST_NODE_TYPES.ArrowFunctionExpression:
6942
+ case AST_NODE_TYPES.NewExpression:
6943
+ case AST_NODE_TYPES.CallExpression:
6944
+ case AST_NODE_TYPES.ClassExpression: return expr;
6945
+ case AST_NODE_TYPES.ConditionalExpression: {
6946
+ const consequent = resolveDynamicValue(context, expr.consequent, isInsideRender, seen);
6947
+ if (consequent != null) return consequent;
6948
+ return resolveDynamicValue(context, expr.alternate, isInsideRender, seen);
6949
+ }
6950
+ case AST_NODE_TYPES.Identifier:
6951
+ case AST_NODE_TYPES.JSXIdentifier: {
6952
+ const resolved = findVariableForIdentifier(context, expr);
6953
+ if (resolved == null) return null;
6954
+ return getDynamicComponentSource(context, resolved, isInsideRender, seen).creationNode;
6955
+ }
6956
+ default: return null;
6957
+ }
6958
+ }
6959
+ function findVariableForIdentifier(context, identifier) {
6960
+ let scope = context.sourceCode.getScope(identifier);
6961
+ while (scope != null) {
6962
+ const variable = scope.variables.find((v) => v.name === identifier.name);
6963
+ if (variable != null) return variable;
6964
+ scope = scope.upper;
6965
+ }
6966
+ return null;
6967
+ }
6968
+ function getDynamicComponentSource(context, variable, isInsideRender, seen = /* @__PURE__ */ new Set()) {
6969
+ if (seen.has(variable)) return {
6970
+ isDynamic: false,
6971
+ creationNode: null
6972
+ };
6973
+ seen.add(variable);
6974
+ for (const def of variable.defs) {
6975
+ const defNode = def.node;
6976
+ if (!isInsideRender(defNode)) continue;
6977
+ if (defNode.type === AST_NODE_TYPES.FunctionDeclaration) return {
6978
+ isDynamic: true,
6979
+ creationNode: defNode
6980
+ };
6981
+ if (defNode.type === AST_NODE_TYPES.ClassDeclaration) return {
6982
+ isDynamic: true,
6983
+ creationNode: defNode
6984
+ };
6985
+ if (defNode.type === AST_NODE_TYPES.VariableDeclarator) {
6986
+ if (defNode.init != null) {
6987
+ const source = resolveDynamicValue(context, defNode.init, isInsideRender, seen);
6988
+ if (source != null) return {
6989
+ isDynamic: true,
6990
+ creationNode: source
6991
+ };
6992
+ }
6993
+ for (const ref of variable.references) {
6994
+ if (!ref.isWrite()) continue;
6995
+ const id = ref.identifier;
6996
+ if (id.parent?.type === AST_NODE_TYPES.AssignmentExpression && id.parent.left === id) {
6997
+ const source = resolveDynamicValue(context, id.parent.right, isInsideRender, seen);
6998
+ if (source != null) return {
6999
+ isDynamic: true,
7000
+ creationNode: source
7001
+ };
7002
+ }
7003
+ }
7004
+ }
7005
+ }
7006
+ return {
7007
+ isDynamic: false,
7008
+ creationNode: null
7009
+ };
7010
+ }
7011
+
6935
7012
  //#endregion
6936
7013
  //#region src/rules/static-components/static-components.ts
6937
7014
  const RULE_NAME$3 = "static-components";
@@ -6939,51 +7016,16 @@ var static_components_default = createRule({
6939
7016
  meta: {
6940
7017
  type: "problem",
6941
7018
  docs: { description: "Validates that components are static, not recreated every render." },
6942
- messages: { default: "Component '{{name}}' is created during render. Components created during render will reset their state each time they are created. Declare components outside of render." },
7019
+ messages: {
7020
+ default: "Cannot create components during render. Components created during render will reset their state each time they are created. Declare components outside of render.",
7021
+ createdHere: "The component is created during render here."
7022
+ },
6943
7023
  schema: []
6944
7024
  },
6945
7025
  name: RULE_NAME$3,
6946
7026
  create: create$3,
6947
7027
  defaultOptions: []
6948
7028
  });
6949
- function findVariableForJSXIdentifier(context, jsxId) {
6950
- let scope = context.sourceCode.getScope(jsxId);
6951
- while (scope != null) {
6952
- const variable = scope.variables.find((v) => v.name === jsxId.name);
6953
- if (variable != null) return variable;
6954
- scope = scope.upper;
6955
- }
6956
- return null;
6957
- }
6958
- function isDynamicallyCreatedValue(node) {
6959
- const expr = Extract.unwrap(node);
6960
- switch (expr.type) {
6961
- case AST_NODE_TYPES.FunctionExpression:
6962
- case AST_NODE_TYPES.ArrowFunctionExpression:
6963
- case AST_NODE_TYPES.NewExpression:
6964
- case AST_NODE_TYPES.CallExpression:
6965
- case AST_NODE_TYPES.ClassExpression: return true;
6966
- case AST_NODE_TYPES.ConditionalExpression: return isDynamicallyCreatedValue(expr.consequent) || isDynamicallyCreatedValue(expr.alternate);
6967
- default: return false;
6968
- }
6969
- }
6970
- function hasDynamicAssignment(variable) {
6971
- for (const ref of variable.references) {
6972
- if (!ref.isWrite()) continue;
6973
- const id = ref.identifier;
6974
- if (id.parent?.type === AST_NODE_TYPES.AssignmentExpression && id.parent.left === id) {
6975
- if (isDynamicallyCreatedValue(id.parent.right)) return true;
6976
- }
6977
- }
6978
- return false;
6979
- }
6980
- function isDynamicallyCreated(node, variable) {
6981
- if (node.type === AST_NODE_TYPES.FunctionDeclaration) return true;
6982
- if (node.type === AST_NODE_TYPES.ClassDeclaration) return true;
6983
- if (node.type === AST_NODE_TYPES.VariableDeclarator && node.init != null) return isDynamicallyCreatedValue(node.init);
6984
- if (node.type === AST_NODE_TYPES.VariableDeclarator && node.init == null && variable != null) return hasDynamicAssignment(variable);
6985
- return false;
6986
- }
6987
7029
  function create$3(context) {
6988
7030
  const hint = core.FunctionComponentDetectionHint.DoNotIncludeJsxWithNumberValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithNullValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithStringValue | core.FunctionComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | core.FunctionComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx | core.FunctionComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayPatternElement | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayExpressionElement | core.FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback;
6989
7031
  const fc = core.getFunctionComponentCollector(context, { hint });
@@ -7009,20 +7051,27 @@ function create$3(context) {
7009
7051
  return false;
7010
7052
  });
7011
7053
  }
7054
+ const isInsideRender = (node) => getEnclosingComponent(node) != null;
7012
7055
  for (const { name, node: jsxNode } of jsxCandidates) {
7013
7056
  const jsxName = jsxNode.name;
7014
- const variable = findVariableForJSXIdentifier(context, jsxName);
7057
+ const variable = findVariableForIdentifier(context, jsxName);
7015
7058
  if (variable == null || variable.defs.length === 0) continue;
7016
7059
  const def = variable.defs.at(0);
7017
7060
  if (def == null) continue;
7018
7061
  const defNode = def.node;
7019
7062
  if (getEnclosingComponent(defNode) == null) continue;
7020
- if (!isDynamicallyCreated(defNode, variable)) continue;
7063
+ const result = getDynamicComponentSource(context, variable, isInsideRender);
7064
+ if (!result.isDynamic) continue;
7021
7065
  context.report({
7022
7066
  data: { name },
7023
7067
  messageId: "default",
7024
7068
  node: jsxNode.name
7025
7069
  });
7070
+ if (result.creationNode != null) context.report({
7071
+ data: { name },
7072
+ messageId: "createdHere",
7073
+ node: result.creationNode
7074
+ });
7026
7075
  }
7027
7076
  }
7028
7077
  });
@@ -7149,11 +7198,11 @@ var use_memo_default = createRule({
7149
7198
  type: "problem",
7150
7199
  docs: { description: "Validates that 'useMemo' is called with a callback that returns a value." },
7151
7200
  messages: {
7152
- mustReturnAValue: "useMemo() callbacks must return a value. This useMemo() callback doesn't return a value. useMemo() is for computing and caching values, not for arbitrary side effects.",
7153
- noAsyncOrGeneratorFunctions: "useMemo() callbacks may not be async or generator functions. useMemo() callbacks are called once and must synchronously return a value.",
7154
- noParameters: "useMemo() callbacks may not accept parameters. useMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation.",
7155
- noReassigningOuterVariables: "useMemo() callbacks may not reassign variables declared outside of the callback. useMemo() callbacks must be pure functions and cannot reassign variables defined outside of the callback function.",
7156
- resultMustBeUsed: "useMemo() result is unused. This useMemo() value is unused. useMemo() is for computing and caching values, not for arbitrary side effects."
7201
+ noParameters: "useMemo() callbacks may not accept parameters.\n\nuseMemo() callbacks are called by React to cache calculations across re-renders. They should not take parameters. Instead, directly reference the props, state, or local variables needed for the computation.",
7202
+ noAsyncOrGeneratorFunctions: "useMemo() callbacks may not be async or generator functions.\n\nuseMemo() callbacks are called once and must synchronously return a value.",
7203
+ noReassigningOuterVariables: "useMemo() callbacks may not reassign variables declared outside of the callback.\n\nuseMemo() callbacks must be pure functions and cannot reassign variables defined outside of the callback function.",
7204
+ mustReturnAValue: "useMemo() callbacks must return a value.\n\nThis useMemo() callback doesn't return a value. useMemo() is for computing and caching values, not for arbitrary side effects.",
7205
+ resultMustBeUsed: "useMemo() result is unused.\n\nThis useMemo() value is unused. useMemo() is for computing and caching values, not for arbitrary side effects."
7157
7206
  },
7158
7207
  schema: []
7159
7208
  },
@@ -7185,7 +7234,7 @@ function create$1(context) {
7185
7234
  if (!core.isUseMemoCall(context, node)) return;
7186
7235
  let parent = node.parent;
7187
7236
  while (Check.isTypeExpression(parent)) parent = parent.parent;
7188
- if (!(parent.type === AST_NODE_TYPES.VariableDeclarator || parent.type === AST_NODE_TYPES.AssignmentExpression || parent.type === AST_NODE_TYPES.AssignmentPattern || parent.type === AST_NODE_TYPES.Property || parent.type === AST_NODE_TYPES.ReturnStatement || parent.type === AST_NODE_TYPES.JSXExpressionContainer || parent.type === AST_NODE_TYPES.CallExpression || parent.type === AST_NODE_TYPES.NewExpression || parent.type === AST_NODE_TYPES.ArrayExpression || parent.type === AST_NODE_TYPES.ConditionalExpression || parent.type === AST_NODE_TYPES.LogicalExpression || parent.type === AST_NODE_TYPES.SequenceExpression || parent.type === AST_NODE_TYPES.SpreadElement || parent.type === AST_NODE_TYPES.TemplateLiteral || parent.type === AST_NODE_TYPES.BinaryExpression || parent.type === AST_NODE_TYPES.UnaryExpression || parent.type === AST_NODE_TYPES.MemberExpression || parent.type === AST_NODE_TYPES.TaggedTemplateExpression || parent.type === AST_NODE_TYPES.ChainExpression || parent.type === AST_NODE_TYPES.ArrowFunctionExpression)) {
7237
+ if (!(parent.type === AST_NODE_TYPES.VariableDeclarator || parent.type === AST_NODE_TYPES.AssignmentExpression || parent.type === AST_NODE_TYPES.AssignmentPattern || parent.type === AST_NODE_TYPES.Property || parent.type === AST_NODE_TYPES.ReturnStatement || parent.type === AST_NODE_TYPES.JSXExpressionContainer || parent.type === AST_NODE_TYPES.CallExpression || parent.type === AST_NODE_TYPES.NewExpression || parent.type === AST_NODE_TYPES.ArrayExpression || parent.type === AST_NODE_TYPES.ConditionalExpression || parent.type === AST_NODE_TYPES.LogicalExpression || parent.type === AST_NODE_TYPES.SequenceExpression || parent.type === AST_NODE_TYPES.SpreadElement || parent.type === AST_NODE_TYPES.TemplateLiteral || parent.type === AST_NODE_TYPES.BinaryExpression || parent.type === AST_NODE_TYPES.UnaryExpression || parent.type === AST_NODE_TYPES.MemberExpression || parent.type === AST_NODE_TYPES.TaggedTemplateExpression || parent.type === AST_NODE_TYPES.ChainExpression || parent.type === AST_NODE_TYPES.ArrowFunctionExpression || parent.type === AST_NODE_TYPES.ForOfStatement || parent.type === AST_NODE_TYPES.ForInStatement)) {
7189
7238
  context.report({
7190
7239
  messageId: "resultMustBeUsed",
7191
7240
  node
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "5.5.2-beta.0",
3
+ "version": "5.5.3-beta.0",
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",
@@ -46,12 +46,12 @@
46
46
  "string-ts": "^2.3.1",
47
47
  "ts-api-utils": "^2.5.0",
48
48
  "ts-pattern": "^5.9.0",
49
- "@eslint-react/core": "5.5.2-beta.0",
50
- "@eslint-react/jsx": "5.5.2-beta.0",
51
- "@eslint-react/var": "5.5.2-beta.0",
52
- "@eslint-react/shared": "5.5.2-beta.0",
53
- "@eslint-react/eslint": "5.5.2-beta.0",
54
- "@eslint-react/ast": "5.5.2-beta.0"
49
+ "@eslint-react/ast": "5.5.3-beta.0",
50
+ "@eslint-react/core": "5.5.3-beta.0",
51
+ "@eslint-react/eslint": "5.5.3-beta.0",
52
+ "@eslint-react/jsx": "5.5.3-beta.0",
53
+ "@eslint-react/shared": "5.5.3-beta.0",
54
+ "@eslint-react/var": "5.5.3-beta.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/react": "^19.2.14",
@@ -63,8 +63,8 @@
63
63
  "tsdown": "^0.21.10",
64
64
  "tsl": "^1.0.30",
65
65
  "tsl-dx": "^0.12.0",
66
- "@local/configs": "0.0.0",
67
- "@local/eff": "3.0.0-beta.72"
66
+ "@local/eff": "3.0.0-beta.72",
67
+ "@local/configs": "0.0.0"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "eslint": "^10.2.1",