eslint-plugin-react-hooks 6.1.0-canary-6de32a5a-20250822 → 6.1.0-canary-33a1095d-20250827

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.
@@ -17993,14 +17993,20 @@ var ErrorCategory;
17993
17993
  ErrorCategory["Fire"] = "Fire";
17994
17994
  ErrorCategory["FBT"] = "FBT";
17995
17995
  })(ErrorCategory || (ErrorCategory = {}));
17996
+ const RULE_NAME_PATTERN = /^[a-z]+(-[a-z]+)*$/;
17996
17997
  function getRuleForCategory(category) {
17998
+ const rule = getRuleForCategoryImpl(category);
17999
+ invariant(RULE_NAME_PATTERN.test(rule.name), `Invalid rule name, got '${rule.name}' but rules must match ${RULE_NAME_PATTERN.toString()}`);
18000
+ return rule;
18001
+ }
18002
+ function getRuleForCategoryImpl(category) {
17997
18003
  switch (category) {
17998
18004
  case ErrorCategory.AutomaticEffectDependencies: {
17999
18005
  return {
18000
18006
  category,
18001
18007
  name: 'automatic-effect-dependencies',
18002
18008
  description: 'Verifies that automatic effect dependencies are compiled if opted-in',
18003
- recommended: true,
18009
+ recommended: false,
18004
18010
  };
18005
18011
  }
18006
18012
  case ErrorCategory.CapitalizedCalls: {
@@ -18015,7 +18021,7 @@ function getRuleForCategory(category) {
18015
18021
  return {
18016
18022
  category,
18017
18023
  name: 'config',
18018
- description: 'Validates the configuration',
18024
+ description: 'Validates the compiler configuration options',
18019
18025
  recommended: true,
18020
18026
  };
18021
18027
  }
@@ -18039,7 +18045,7 @@ function getRuleForCategory(category) {
18039
18045
  return {
18040
18046
  category,
18041
18047
  name: 'set-state-in-effect',
18042
- description: 'Validates against calling setState synchronously in an effect',
18048
+ description: 'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
18043
18049
  recommended: true,
18044
18050
  };
18045
18051
  }
@@ -18047,7 +18053,7 @@ function getRuleForCategory(category) {
18047
18053
  return {
18048
18054
  category,
18049
18055
  name: 'error-boundaries',
18050
- description: 'Validates usage of error boundaries instead of try/catch for errors in JSX',
18056
+ description: 'Validates usage of error boundaries instead of try/catch for errors in child components',
18051
18057
  recommended: true,
18052
18058
  };
18053
18059
  }
@@ -18071,7 +18077,7 @@ function getRuleForCategory(category) {
18071
18077
  return {
18072
18078
  category,
18073
18079
  name: 'gating',
18074
- description: 'Validates configuration of gating mode',
18080
+ description: 'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)',
18075
18081
  recommended: true,
18076
18082
  };
18077
18083
  }
@@ -18079,7 +18085,8 @@ function getRuleForCategory(category) {
18079
18085
  return {
18080
18086
  category,
18081
18087
  name: 'globals',
18082
- description: 'Validates against assignment/mutation of globals during render',
18088
+ description: 'Validates against assignment/mutation of globals during render, part of ensuring that ' +
18089
+ '[side effects must render outside of render](https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)',
18083
18090
  recommended: true,
18084
18091
  };
18085
18092
  }
@@ -18095,7 +18102,7 @@ function getRuleForCategory(category) {
18095
18102
  return {
18096
18103
  category,
18097
18104
  name: 'immutability',
18098
- description: 'Validates that immutable values (props, state, etc) are not mutated',
18105
+ description: 'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)',
18099
18106
  recommended: true,
18100
18107
  };
18101
18108
  }
@@ -18111,7 +18118,9 @@ function getRuleForCategory(category) {
18111
18118
  return {
18112
18119
  category,
18113
18120
  name: 'preserve-manual-memoization',
18114
- description: 'Validates that existing manual memoized is preserved by the compiler',
18121
+ description: 'Validates that existing manual memoized is preserved by the compiler. ' +
18122
+ 'React Compiler will only compile components and hooks if its inference ' +
18123
+ '[matches or exceeds the existing manual memoization](https://react.dev/learn/react-compiler/introduction#what-should-i-do-about-usememo-usecallback-and-reactmemo)',
18115
18124
  recommended: true,
18116
18125
  };
18117
18126
  }
@@ -18119,7 +18128,7 @@ function getRuleForCategory(category) {
18119
18128
  return {
18120
18129
  category,
18121
18130
  name: 'purity',
18122
- description: 'Validates that the component/hook is pure, and does not call known-impure functions',
18131
+ description: 'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions',
18123
18132
  recommended: true,
18124
18133
  };
18125
18134
  }
@@ -18127,7 +18136,7 @@ function getRuleForCategory(category) {
18127
18136
  return {
18128
18137
  category,
18129
18138
  name: 'refs',
18130
- description: 'Validates correct usage of refs, not reading/writing during render',
18139
+ description: 'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)',
18131
18140
  recommended: true,
18132
18141
  };
18133
18142
  }
@@ -18135,7 +18144,7 @@ function getRuleForCategory(category) {
18135
18144
  return {
18136
18145
  category,
18137
18146
  name: 'set-state-in-render',
18138
- description: 'Validates against setting state during render',
18147
+ description: 'Validates against setting state during render, which can trigger additional renders and potential infinite render loops',
18139
18148
  recommended: true,
18140
18149
  };
18141
18150
  }
@@ -18143,7 +18152,7 @@ function getRuleForCategory(category) {
18143
18152
  return {
18144
18153
  category,
18145
18154
  name: 'static-components',
18146
- description: 'Validates that components are static, not recreated every render',
18155
+ description: 'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering',
18147
18156
  recommended: true,
18148
18157
  };
18149
18158
  }
@@ -18175,7 +18184,7 @@ function getRuleForCategory(category) {
18175
18184
  return {
18176
18185
  category,
18177
18186
  name: 'unsupported-syntax',
18178
- description: 'Validates against syntax that we do not plan to support',
18187
+ description: 'Validates against syntax that we do not plan to support in React Compiler',
18179
18188
  recommended: true,
18180
18189
  };
18181
18190
  }
@@ -18183,7 +18192,7 @@ function getRuleForCategory(category) {
18183
18192
  return {
18184
18193
  category,
18185
18194
  name: 'use-memo',
18186
- description: 'Validates usage of the useMemo() hook',
18195
+ description: 'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
18187
18196
  recommended: true,
18188
18197
  };
18189
18198
  }
@@ -19458,7 +19467,8 @@ function printType(type) {
19458
19467
  return `:T${type.kind}<${type.shapeId}>`;
19459
19468
  }
19460
19469
  else if (type.kind === 'Function' && type.shapeId != null) {
19461
- return `:T${type.kind}<${type.shapeId}>`;
19470
+ const returnType = printType(type.return);
19471
+ return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
19462
19472
  }
19463
19473
  else {
19464
19474
  return `:T${type.kind}`;
@@ -40443,6 +40453,18 @@ function computeSignatureForInstruction(context, env, instr) {
40443
40453
  });
40444
40454
  }
40445
40455
  }
40456
+ for (const prop of value.props) {
40457
+ if (prop.kind === 'JsxAttribute' &&
40458
+ prop.place.identifier.type.kind === 'Function' &&
40459
+ (isJsxType(prop.place.identifier.type.return) ||
40460
+ (prop.place.identifier.type.return.kind === 'Phi' &&
40461
+ prop.place.identifier.type.return.operands.some(operand => isJsxType(operand))))) {
40462
+ effects.push({
40463
+ kind: 'Render',
40464
+ place: prop.place,
40465
+ });
40466
+ }
40467
+ }
40446
40468
  }
40447
40469
  break;
40448
40470
  }
@@ -46736,6 +46758,14 @@ class Unifier {
46736
46758
  if (type.kind === 'Phi') {
46737
46759
  return { kind: 'Phi', operands: type.operands.map(o => this.get(o)) };
46738
46760
  }
46761
+ if (type.kind === 'Function') {
46762
+ return {
46763
+ kind: 'Function',
46764
+ isConstructor: type.isConstructor,
46765
+ shapeId: type.shapeId,
46766
+ return: this.get(type.return),
46767
+ };
46768
+ }
46739
46769
  return type;
46740
46770
  }
46741
46771
  }
@@ -17984,14 +17984,20 @@ var ErrorCategory;
17984
17984
  ErrorCategory["Fire"] = "Fire";
17985
17985
  ErrorCategory["FBT"] = "FBT";
17986
17986
  })(ErrorCategory || (ErrorCategory = {}));
17987
+ const RULE_NAME_PATTERN = /^[a-z]+(-[a-z]+)*$/;
17987
17988
  function getRuleForCategory(category) {
17989
+ const rule = getRuleForCategoryImpl(category);
17990
+ invariant(RULE_NAME_PATTERN.test(rule.name), `Invalid rule name, got '${rule.name}' but rules must match ${RULE_NAME_PATTERN.toString()}`);
17991
+ return rule;
17992
+ }
17993
+ function getRuleForCategoryImpl(category) {
17988
17994
  switch (category) {
17989
17995
  case ErrorCategory.AutomaticEffectDependencies: {
17990
17996
  return {
17991
17997
  category,
17992
17998
  name: 'automatic-effect-dependencies',
17993
17999
  description: 'Verifies that automatic effect dependencies are compiled if opted-in',
17994
- recommended: true,
18000
+ recommended: false,
17995
18001
  };
17996
18002
  }
17997
18003
  case ErrorCategory.CapitalizedCalls: {
@@ -18006,7 +18012,7 @@ function getRuleForCategory(category) {
18006
18012
  return {
18007
18013
  category,
18008
18014
  name: 'config',
18009
- description: 'Validates the configuration',
18015
+ description: 'Validates the compiler configuration options',
18010
18016
  recommended: true,
18011
18017
  };
18012
18018
  }
@@ -18030,7 +18036,7 @@ function getRuleForCategory(category) {
18030
18036
  return {
18031
18037
  category,
18032
18038
  name: 'set-state-in-effect',
18033
- description: 'Validates against calling setState synchronously in an effect',
18039
+ description: 'Validates against calling setState synchronously in an effect, which can lead to re-renders that degrade performance',
18034
18040
  recommended: true,
18035
18041
  };
18036
18042
  }
@@ -18038,7 +18044,7 @@ function getRuleForCategory(category) {
18038
18044
  return {
18039
18045
  category,
18040
18046
  name: 'error-boundaries',
18041
- description: 'Validates usage of error boundaries instead of try/catch for errors in JSX',
18047
+ description: 'Validates usage of error boundaries instead of try/catch for errors in child components',
18042
18048
  recommended: true,
18043
18049
  };
18044
18050
  }
@@ -18062,7 +18068,7 @@ function getRuleForCategory(category) {
18062
18068
  return {
18063
18069
  category,
18064
18070
  name: 'gating',
18065
- description: 'Validates configuration of gating mode',
18071
+ description: 'Validates configuration of [gating mode](https://react.dev/reference/react-compiler/gating)',
18066
18072
  recommended: true,
18067
18073
  };
18068
18074
  }
@@ -18070,7 +18076,8 @@ function getRuleForCategory(category) {
18070
18076
  return {
18071
18077
  category,
18072
18078
  name: 'globals',
18073
- description: 'Validates against assignment/mutation of globals during render',
18079
+ description: 'Validates against assignment/mutation of globals during render, part of ensuring that ' +
18080
+ '[side effects must render outside of render](https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)',
18074
18081
  recommended: true,
18075
18082
  };
18076
18083
  }
@@ -18086,7 +18093,7 @@ function getRuleForCategory(category) {
18086
18093
  return {
18087
18094
  category,
18088
18095
  name: 'immutability',
18089
- description: 'Validates that immutable values (props, state, etc) are not mutated',
18096
+ description: 'Validates against mutating props, state, and other values that [are immutable](https://react.dev/reference/rules/components-and-hooks-must-be-pure#props-and-state-are-immutable)',
18090
18097
  recommended: true,
18091
18098
  };
18092
18099
  }
@@ -18102,7 +18109,9 @@ function getRuleForCategory(category) {
18102
18109
  return {
18103
18110
  category,
18104
18111
  name: 'preserve-manual-memoization',
18105
- description: 'Validates that existing manual memoized is preserved by the compiler',
18112
+ description: 'Validates that existing manual memoized is preserved by the compiler. ' +
18113
+ 'React Compiler will only compile components and hooks if its inference ' +
18114
+ '[matches or exceeds the existing manual memoization](https://react.dev/learn/react-compiler/introduction#what-should-i-do-about-usememo-usecallback-and-reactmemo)',
18106
18115
  recommended: true,
18107
18116
  };
18108
18117
  }
@@ -18110,7 +18119,7 @@ function getRuleForCategory(category) {
18110
18119
  return {
18111
18120
  category,
18112
18121
  name: 'purity',
18113
- description: 'Validates that the component/hook is pure, and does not call known-impure functions',
18122
+ description: 'Validates that [components/hooks are pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure) by checking that they do not call known-impure functions',
18114
18123
  recommended: true,
18115
18124
  };
18116
18125
  }
@@ -18118,7 +18127,7 @@ function getRuleForCategory(category) {
18118
18127
  return {
18119
18128
  category,
18120
18129
  name: 'refs',
18121
- description: 'Validates correct usage of refs, not reading/writing during render',
18130
+ description: 'Validates correct usage of refs, not reading/writing during render. See the "pitfalls" section in [`useRef()` usage](https://react.dev/reference/react/useRef#usage)',
18122
18131
  recommended: true,
18123
18132
  };
18124
18133
  }
@@ -18126,7 +18135,7 @@ function getRuleForCategory(category) {
18126
18135
  return {
18127
18136
  category,
18128
18137
  name: 'set-state-in-render',
18129
- description: 'Validates against setting state during render',
18138
+ description: 'Validates against setting state during render, which can trigger additional renders and potential infinite render loops',
18130
18139
  recommended: true,
18131
18140
  };
18132
18141
  }
@@ -18134,7 +18143,7 @@ function getRuleForCategory(category) {
18134
18143
  return {
18135
18144
  category,
18136
18145
  name: 'static-components',
18137
- description: 'Validates that components are static, not recreated every render',
18146
+ description: 'Validates that components are static, not recreated every render. Components that are recreated dynamically can reset state and trigger excessive re-rendering',
18138
18147
  recommended: true,
18139
18148
  };
18140
18149
  }
@@ -18166,7 +18175,7 @@ function getRuleForCategory(category) {
18166
18175
  return {
18167
18176
  category,
18168
18177
  name: 'unsupported-syntax',
18169
- description: 'Validates against syntax that we do not plan to support',
18178
+ description: 'Validates against syntax that we do not plan to support in React Compiler',
18170
18179
  recommended: true,
18171
18180
  };
18172
18181
  }
@@ -18174,7 +18183,7 @@ function getRuleForCategory(category) {
18174
18183
  return {
18175
18184
  category,
18176
18185
  name: 'use-memo',
18177
- description: 'Validates usage of the useMemo() hook',
18186
+ description: 'Validates usage of the useMemo() hook against common mistakes. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
18178
18187
  recommended: true,
18179
18188
  };
18180
18189
  }
@@ -19449,7 +19458,8 @@ function printType(type) {
19449
19458
  return `:T${type.kind}<${type.shapeId}>`;
19450
19459
  }
19451
19460
  else if (type.kind === 'Function' && type.shapeId != null) {
19452
- return `:T${type.kind}<${type.shapeId}>`;
19461
+ const returnType = printType(type.return);
19462
+ return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? `: ${returnType}` : ''}`;
19453
19463
  }
19454
19464
  else {
19455
19465
  return `:T${type.kind}`;
@@ -40270,6 +40280,18 @@ function computeSignatureForInstruction(context, env, instr) {
40270
40280
  });
40271
40281
  }
40272
40282
  }
40283
+ for (const prop of value.props) {
40284
+ if (prop.kind === 'JsxAttribute' &&
40285
+ prop.place.identifier.type.kind === 'Function' &&
40286
+ (isJsxType(prop.place.identifier.type.return) ||
40287
+ (prop.place.identifier.type.return.kind === 'Phi' &&
40288
+ prop.place.identifier.type.return.operands.some(operand => isJsxType(operand))))) {
40289
+ effects.push({
40290
+ kind: 'Render',
40291
+ place: prop.place,
40292
+ });
40293
+ }
40294
+ }
40273
40295
  }
40274
40296
  break;
40275
40297
  }
@@ -46563,6 +46585,14 @@ class Unifier {
46563
46585
  if (type.kind === 'Phi') {
46564
46586
  return { kind: 'Phi', operands: type.operands.map(o => this.get(o)) };
46565
46587
  }
46588
+ if (type.kind === 'Function') {
46589
+ return {
46590
+ kind: 'Function',
46591
+ isConstructor: type.isConstructor,
46592
+ shapeId: type.shapeId,
46593
+ return: this.get(type.return),
46594
+ };
46595
+ }
46566
46596
  return type;
46567
46597
  }
46568
46598
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks",
3
3
  "description": "ESLint rules for React Hooks",
4
- "version": "6.1.0-canary-6de32a5a-20250822",
4
+ "version": "6.1.0-canary-33a1095d-20250827",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",
@@ -41,7 +41,7 @@
41
41
  "dependencies": {
42
42
  "@babel/core": "^7.24.4",
43
43
  "@babel/parser": "^7.24.4",
44
- "@babel/plugin-transform-private-methods": "^7.24.4",
44
+ "@babel/plugin-proposal-private-methods": "^7.18.6",
45
45
  "hermes-parser": "^0.25.1",
46
46
  "zod": "^3.22.4",
47
47
  "zod-validation-error": "^3.0.3"