eslint-plugin-react-hooks-extra 1.12.5-next.5 → 1.13.0-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.
package/README.md CHANGED
@@ -31,7 +31,7 @@ export default [
31
31
  },
32
32
  rules: {
33
33
  // react-hooks-extra recommended rules
34
- "hooks-extra/ensure-custom-hooks-using-other-hooks": "warn",
34
+ "hooks-extra/no-redundant-custom-hook": "warn",
35
35
  "hooks-extra/no-direct-set-state-in-use-effect": "warn",
36
36
  "hooks-extra/prefer-use-state-lazy-initialization": "warn",
37
37
  },
@@ -41,10 +41,10 @@ export default [
41
41
 
42
42
  ## Rules
43
43
 
44
- | Rule | Description | 💼 | 💭 | |
45
- | :--------------------------------------- | :------------------------------------------------------------------------ | :-: | :-: | :-: |
46
- | `ensure-custom-hooks-using-other-hooks` | Warns when custom Hooks that don't use other Hooks. | ✔️ | | |
47
- | `ensure-use-callback-has-non-empty-deps` | Warns when `useCallback` is called with empty dependencies array. | 🧐 | | |
48
- | `ensure-use-memo-has-non-empty-deps` | Warns when `useMemo` is called with empty dependencies array. | 🧐 | | |
49
- | `no-direct-set-state-in-use-effect` | Disallow direct calls to the `set` function of `useState` in `useEffect`. | ✔️ | | |
50
- | `prefer-use-state-lazy-initialization` | Warns function calls made inside `useState` calls. | 🚀 | | |
44
+ | Rule | Description | 💼 | 💭 | |
45
+ | :------------------------------------- | :------------------------------------------------------------------------ | :-: | :-: | :-: |
46
+ | `no-direct-set-state-in-use-effect` | Disallow direct calls to the `set` function of `useState` in `useEffect`. | ✔️ | | |
47
+ | `no-redundant-custom-hook` | Warns when custom Hooks that don't use other Hooks. | ✔️ | | |
48
+ | `no-unnecessary-use-callback` | Disallow unnecessary usage of `useCallback`. | ✔️ | | |
49
+ | `no-unnecessary-use-memo` | Disallow unnecessary usage of `useMemo`. | ✔️ | | |
50
+ | `prefer-use-state-lazy-initialization` | Warns function calls made inside `useState` calls. | 🚀 | | |
package/dist/index.d.mts CHANGED
@@ -5,13 +5,17 @@ declare const meta: {
5
5
  readonly version: string;
6
6
  };
7
7
  declare const rules: {
8
- readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"ensureCustomHooksUsingOtherHooks", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
9
- readonly "ensure-use-callback-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ensureUseCallbackHasNonEmptyDeps", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
10
- readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ensureUseMemoHasNonEmptyDeps", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
11
8
  readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
9
+ readonly "no-redundant-custom-hook": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
10
+ readonly "no-unnecessary-use-callback": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseCallback", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
11
+ readonly "no-unnecessary-use-memo": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
+ readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"preferUseStateLazyInitialization", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
13
+ /** @deprecated Use `no-redundant-custom-hook` instead */
14
+ readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
15
+ /** @deprecated Use `no-unnecessary-use-memo` instead */
16
+ readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
17
  /** @deprecated Use `no-direct-set-state-in-use-effect` instead */
13
18
  readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
14
- readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"preferUseStateLazyInitialization", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
15
19
  };
16
20
 
17
21
  export { meta, rules };
package/dist/index.d.ts CHANGED
@@ -5,13 +5,17 @@ declare const meta: {
5
5
  readonly version: string;
6
6
  };
7
7
  declare const rules: {
8
- readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"ensureCustomHooksUsingOtherHooks", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
9
- readonly "ensure-use-callback-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ensureUseCallbackHasNonEmptyDeps", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
10
- readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ensureUseMemoHasNonEmptyDeps", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
11
8
  readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
9
+ readonly "no-redundant-custom-hook": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
10
+ readonly "no-unnecessary-use-callback": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseCallback", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
11
+ readonly "no-unnecessary-use-memo": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
+ readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"preferUseStateLazyInitialization", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
13
+ /** @deprecated Use `no-redundant-custom-hook` instead */
14
+ readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
15
+ /** @deprecated Use `no-unnecessary-use-memo` instead */
16
+ readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
17
  /** @deprecated Use `no-direct-set-state-in-use-effect` instead */
13
18
  readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
14
- readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"preferUseStateLazyInitialization", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
15
19
  };
16
20
 
17
21
  export { meta, rules };
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  'use strict';
2
2
 
3
+ var ast = require('@eslint-react/ast');
3
4
  var core = require('@eslint-react/core');
4
5
  var shared = require('@eslint-react/shared');
5
- var ast = require('@eslint-react/ast');
6
6
  var tools = require('@eslint-react/tools');
7
7
  var _var = require('@eslint-react/var');
8
8
  var types = require('@typescript-eslint/types');
9
- var astUtils = require('@typescript-eslint/utils/ast-utils');
10
9
  var tsPattern = require('ts-pattern');
10
+ var astUtils = require('@typescript-eslint/utils/ast-utils');
11
11
 
12
12
  // package.json
13
13
  var name = "eslint-plugin-react-hooks-extra";
14
- var version = "1.12.5-next.5";
14
+ var version = "1.13.0-beta.0";
15
15
  var createRule = shared.createRuleForPlugin("hooks-extra");
16
16
  function isFromHookCall(name2, context, settings, predicate = tools.F.constTrue) {
17
17
  const hookAlias = settings.additionalHooks?.[name2] ?? [];
@@ -92,201 +92,8 @@ function isVariableDeclaratorFromHookCall(node) {
92
92
  }
93
93
  }
94
94
 
95
- // src/rules/ensure-custom-hooks-using-other-hooks.ts
96
- var RULE_NAME = "ensure-custom-hooks-using-other-hooks";
97
- var ensure_custom_hooks_using_other_hooks_default = createRule({
98
- meta: {
99
- type: "problem",
100
- docs: {
101
- description: "enforce custom hooks using other hooks"
102
- },
103
- messages: {
104
- ensureCustomHooksUsingOtherHooks: "A custom hook '{{name}}' should use other hooks."
105
- },
106
- schema: []
107
- },
108
- name: RULE_NAME,
109
- create(context) {
110
- if (!context.sourceCode.text.includes("use")) return {};
111
- const { ctx, listeners } = core.useHookCollector();
112
- return {
113
- ...listeners,
114
- "Program:exit"(node) {
115
- const allHooks = ctx.getAllHooks(node);
116
- for (const { name: name2, node: node2, hookCalls } of allHooks.values()) {
117
- if (hookCalls.length > 0) continue;
118
- context.report({
119
- messageId: "ensureCustomHooksUsingOtherHooks",
120
- node: node2,
121
- data: {
122
- name: name2.value
123
- }
124
- });
125
- }
126
- }
127
- };
128
- },
129
- defaultOptions: []
130
- });
131
- var RULE_NAME2 = "ensure-use-callback-has-non-empty-deps";
132
- var ensure_use_callback_has_non_empty_deps_default = createRule({
133
- meta: {
134
- type: "problem",
135
- docs: {
136
- description: "enforce 'useCallback' has non-empty dependencies array"
137
- },
138
- messages: {
139
- ensureUseCallbackHasNonEmptyDeps: "An 'useCallback' should have a non-empty dependencies array."
140
- },
141
- schema: []
142
- },
143
- name: RULE_NAME2,
144
- create(context) {
145
- if (!context.sourceCode.text.includes("use")) return {};
146
- const alias = shared.decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
147
- return {
148
- CallExpression(node) {
149
- if (!core.isReactHookCall(node)) return;
150
- const initialScope = context.sourceCode.getScope(node);
151
- if (!core.isUseCallbackCall(node, context) && !alias.some(core.isReactHookCallWithNameLoose(node))) {
152
- return;
153
- }
154
- const scope = context.sourceCode.getScope(node);
155
- const component = scope.block;
156
- if (!ast.isFunction(component)) return;
157
- const [cb, deps] = node.arguments;
158
- if (!deps) {
159
- context.report({
160
- messageId: "ensureUseCallbackHasNonEmptyDeps",
161
- node
162
- });
163
- return;
164
- }
165
- const hasEmptyDeps = tools.F.pipe(
166
- tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
167
- return tools.F.pipe(
168
- _var.findVariable(n.name, initialScope),
169
- tools.O.flatMap(_var.getVariableNode(0)),
170
- tools.O.filter(ast.is(types.AST_NODE_TYPES.ArrayExpression))
171
- );
172
- }).otherwise(tools.O.none),
173
- tools.O.exists((x) => x.elements.length === 0)
174
- );
175
- if (!hasEmptyDeps) return;
176
- if (!cb) {
177
- context.report({
178
- messageId: "ensureUseCallbackHasNonEmptyDeps",
179
- node
180
- });
181
- return;
182
- }
183
- const isReferencedToComponentScope = tools.F.pipe(
184
- tsPattern.match(cb).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
185
- if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
186
- return tools.O.some(n.body);
187
- }
188
- return tools.O.some(n);
189
- }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
190
- return tools.F.pipe(
191
- _var.findVariable(n.name, initialScope),
192
- tools.O.flatMap(_var.getVariableNode(0)),
193
- tools.O.filter(ast.isFunction)
194
- );
195
- }).otherwise(tools.O.none),
196
- tools.O.map((n) => context.sourceCode.getScope(n)),
197
- tools.O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
198
- tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
199
- );
200
- if (isReferencedToComponentScope) return;
201
- context.report({
202
- messageId: "ensureUseCallbackHasNonEmptyDeps",
203
- node
204
- });
205
- }
206
- };
207
- },
208
- defaultOptions: []
209
- });
210
- var RULE_NAME3 = "ensure-use-memo-has-non-empty-deps";
211
- var ensure_use_memo_has_non_empty_deps_default = createRule({
212
- meta: {
213
- type: "problem",
214
- docs: {
215
- description: "enforce 'useMemo' has non-empty dependencies array"
216
- },
217
- messages: {
218
- ensureUseMemoHasNonEmptyDeps: "An 'useMemo' should have a non-empty dependencies array."
219
- },
220
- schema: []
221
- },
222
- name: RULE_NAME3,
223
- create(context) {
224
- if (!context.sourceCode.text.includes("use")) return {};
225
- const alias = shared.decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
226
- return {
227
- CallExpression(node) {
228
- if (!core.isReactHookCall(node)) return;
229
- const initialScope = context.sourceCode.getScope(node);
230
- if (!core.isUseMemoCall(node, context) && !alias.some(core.isReactHookCallWithNameLoose(node))) {
231
- return;
232
- }
233
- const scope = context.sourceCode.getScope(node);
234
- const component = scope.block;
235
- if (!ast.isFunction(component)) return;
236
- const [cb, deps] = node.arguments;
237
- if (!deps) {
238
- context.report({
239
- messageId: "ensureUseMemoHasNonEmptyDeps",
240
- node
241
- });
242
- return;
243
- }
244
- const hasEmptyDeps = tools.F.pipe(
245
- tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
246
- return tools.F.pipe(
247
- _var.findVariable(n.name, initialScope),
248
- tools.O.flatMap(_var.getVariableNode(0)),
249
- tools.O.filter(ast.is(types.AST_NODE_TYPES.ArrayExpression))
250
- );
251
- }).otherwise(tools.O.none),
252
- tools.O.exists((x) => x.elements.length === 0)
253
- );
254
- if (!hasEmptyDeps) return;
255
- if (!cb) {
256
- context.report({
257
- messageId: "ensureUseMemoHasNonEmptyDeps",
258
- node
259
- });
260
- return;
261
- }
262
- const isReferencedToComponentScope = tools.F.pipe(
263
- tsPattern.match(cb).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
264
- if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
265
- return tools.O.some(n.body);
266
- }
267
- return tools.O.some(n);
268
- }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
269
- return tools.F.pipe(
270
- _var.findVariable(n.name, initialScope),
271
- tools.O.flatMap(_var.getVariableNode(0)),
272
- tools.O.filter(ast.isFunction)
273
- );
274
- }).otherwise(tools.O.none),
275
- tools.O.map((n) => context.sourceCode.getScope(n)),
276
- tools.O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
277
- tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
278
- );
279
- if (isReferencedToComponentScope) return;
280
- context.report({
281
- messageId: "ensureUseMemoHasNonEmptyDeps",
282
- node
283
- });
284
- }
285
- };
286
- },
287
- defaultOptions: []
288
- });
289
- var RULE_NAME4 = "no-direct-set-state-in-use-effect";
95
+ // src/rules/no-direct-set-state-in-use-effect.ts
96
+ var RULE_NAME = "no-direct-set-state-in-use-effect";
290
97
  var no_direct_set_state_in_use_effect_default = createRule({
291
98
  meta: {
292
99
  type: "problem",
@@ -298,7 +105,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
298
105
  },
299
106
  schema: []
300
107
  },
301
- name: RULE_NAME4,
108
+ name: RULE_NAME,
302
109
  create(context) {
303
110
  if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
304
111
  const settings = shared.decodeSettings(context.settings);
@@ -472,6 +279,198 @@ var no_direct_set_state_in_use_effect_default = createRule({
472
279
  },
473
280
  defaultOptions: []
474
281
  });
282
+ var RULE_NAME2 = "no-redundant-custom-hook";
283
+ var no_redundant_custom_hook_default = createRule({
284
+ meta: {
285
+ type: "problem",
286
+ docs: {
287
+ description: "enforce custom hooks to use at least one other hook inside"
288
+ },
289
+ messages: {
290
+ noRedundantCustomHook: "A custom hook '{{name}}' should use at least one other hook."
291
+ },
292
+ schema: []
293
+ },
294
+ name: RULE_NAME2,
295
+ create(context) {
296
+ const { ctx, listeners } = core.useHookCollector();
297
+ return {
298
+ ...listeners,
299
+ "Program:exit"(node) {
300
+ const allHooks = ctx.getAllHooks(node);
301
+ for (const { name: name2, node: node2, hookCalls } of allHooks.values()) {
302
+ if (hookCalls.length > 0) continue;
303
+ context.report({
304
+ messageId: "noRedundantCustomHook",
305
+ node: node2,
306
+ data: {
307
+ name: name2.value
308
+ }
309
+ });
310
+ }
311
+ }
312
+ };
313
+ },
314
+ defaultOptions: []
315
+ });
316
+ var RULE_NAME3 = "no-unnecessary-use-callback";
317
+ var no_unnecessary_use_callback_default = createRule({
318
+ meta: {
319
+ type: "problem",
320
+ docs: {
321
+ description: "disallow unnecessary usage of 'useCallback'"
322
+ },
323
+ messages: {
324
+ noUnnecessaryUseCallback: "An 'useCallback' with empty deps and no references to the component scope may be unnecessary."
325
+ },
326
+ schema: []
327
+ },
328
+ name: RULE_NAME3,
329
+ create(context) {
330
+ if (!context.sourceCode.text.includes("use")) return {};
331
+ const alias = shared.decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
332
+ return {
333
+ CallExpression(node) {
334
+ if (!core.isReactHookCall(node)) return;
335
+ const initialScope = context.sourceCode.getScope(node);
336
+ if (!core.isUseCallbackCall(node, context) && !alias.some(core.isReactHookCallWithNameLoose(node))) {
337
+ return;
338
+ }
339
+ const scope = context.sourceCode.getScope(node);
340
+ const component = scope.block;
341
+ if (!ast.isFunction(component)) return;
342
+ const [cb, deps] = node.arguments;
343
+ if (!deps) {
344
+ context.report({
345
+ messageId: "noUnnecessaryUseCallback",
346
+ node
347
+ });
348
+ return;
349
+ }
350
+ const hasEmptyDeps = tools.F.pipe(
351
+ tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
352
+ return tools.F.pipe(
353
+ _var.findVariable(n.name, initialScope),
354
+ tools.O.flatMap(_var.getVariableNode(0)),
355
+ tools.O.filter(ast.is(types.AST_NODE_TYPES.ArrayExpression))
356
+ );
357
+ }).otherwise(tools.O.none),
358
+ tools.O.exists((x) => x.elements.length === 0)
359
+ );
360
+ if (!hasEmptyDeps) return;
361
+ if (!cb) {
362
+ context.report({
363
+ messageId: "noUnnecessaryUseCallback",
364
+ node
365
+ });
366
+ return;
367
+ }
368
+ const isReferencedToComponentScope = tools.F.pipe(
369
+ tsPattern.match(cb).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
370
+ if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
371
+ return tools.O.some(n.body);
372
+ }
373
+ return tools.O.some(n);
374
+ }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
375
+ return tools.F.pipe(
376
+ _var.findVariable(n.name, initialScope),
377
+ tools.O.flatMap(_var.getVariableNode(0)),
378
+ tools.O.filter(ast.isFunction)
379
+ );
380
+ }).otherwise(tools.O.none),
381
+ tools.O.map((n) => context.sourceCode.getScope(n)),
382
+ tools.O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
383
+ tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
384
+ );
385
+ if (isReferencedToComponentScope) return;
386
+ context.report({
387
+ messageId: "noUnnecessaryUseCallback",
388
+ node
389
+ });
390
+ }
391
+ };
392
+ },
393
+ defaultOptions: []
394
+ });
395
+ var RULE_NAME4 = "no-unnecessary-use-memo";
396
+ var no_unnecessary_use_memo_default = createRule({
397
+ meta: {
398
+ type: "problem",
399
+ docs: {
400
+ description: "disallow unnecessary usage of 'useMemo'"
401
+ },
402
+ messages: {
403
+ noUnnecessaryUseMemo: "An 'useMemo' with empty deps and no references to the component scope may be unnecessary."
404
+ },
405
+ schema: []
406
+ },
407
+ name: RULE_NAME4,
408
+ create(context) {
409
+ if (!context.sourceCode.text.includes("use")) return {};
410
+ const alias = shared.decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
411
+ return {
412
+ CallExpression(node) {
413
+ if (!core.isReactHookCall(node)) return;
414
+ const initialScope = context.sourceCode.getScope(node);
415
+ if (!core.isUseMemoCall(node, context) && !alias.some(core.isReactHookCallWithNameLoose(node))) {
416
+ return;
417
+ }
418
+ const scope = context.sourceCode.getScope(node);
419
+ const component = scope.block;
420
+ if (!ast.isFunction(component)) return;
421
+ const [cb, deps] = node.arguments;
422
+ if (!deps) {
423
+ context.report({
424
+ messageId: "noUnnecessaryUseMemo",
425
+ node
426
+ });
427
+ return;
428
+ }
429
+ const hasEmptyDeps = tools.F.pipe(
430
+ tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
431
+ return tools.F.pipe(
432
+ _var.findVariable(n.name, initialScope),
433
+ tools.O.flatMap(_var.getVariableNode(0)),
434
+ tools.O.filter(ast.is(types.AST_NODE_TYPES.ArrayExpression))
435
+ );
436
+ }).otherwise(tools.O.none),
437
+ tools.O.exists((x) => x.elements.length === 0)
438
+ );
439
+ if (!hasEmptyDeps) return;
440
+ if (!cb) {
441
+ context.report({
442
+ messageId: "noUnnecessaryUseMemo",
443
+ node
444
+ });
445
+ return;
446
+ }
447
+ const isReferencedToComponentScope = tools.F.pipe(
448
+ tsPattern.match(cb).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
449
+ if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
450
+ return tools.O.some(n.body);
451
+ }
452
+ return tools.O.some(n);
453
+ }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
454
+ return tools.F.pipe(
455
+ _var.findVariable(n.name, initialScope),
456
+ tools.O.flatMap(_var.getVariableNode(0)),
457
+ tools.O.filter(ast.isFunction)
458
+ );
459
+ }).otherwise(tools.O.none),
460
+ tools.O.map((n) => context.sourceCode.getScope(n)),
461
+ tools.O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
462
+ tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
463
+ );
464
+ if (isReferencedToComponentScope) return;
465
+ context.report({
466
+ messageId: "noUnnecessaryUseMemo",
467
+ node
468
+ });
469
+ }
470
+ };
471
+ },
472
+ defaultOptions: []
473
+ });
475
474
  var RULE_NAME5 = "prefer-use-state-lazy-initialization";
476
475
  var ALLOW_LIST = ["Boolean", "String", "Number"];
477
476
  var prefer_use_state_lazy_initialization_default = createRule({
@@ -516,13 +515,18 @@ var meta = {
516
515
  version
517
516
  };
518
517
  var rules = {
519
- "ensure-custom-hooks-using-other-hooks": ensure_custom_hooks_using_other_hooks_default,
520
- "ensure-use-callback-has-non-empty-deps": ensure_use_callback_has_non_empty_deps_default,
521
- "ensure-use-memo-has-non-empty-deps": ensure_use_memo_has_non_empty_deps_default,
522
518
  "no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
519
+ "no-redundant-custom-hook": no_redundant_custom_hook_default,
520
+ "no-unnecessary-use-callback": no_unnecessary_use_callback_default,
521
+ "no-unnecessary-use-memo": no_unnecessary_use_memo_default,
522
+ "prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default,
523
+ // Deprecated Rules
524
+ /** @deprecated Use `no-redundant-custom-hook` instead */
525
+ "ensure-custom-hooks-using-other-hooks": no_redundant_custom_hook_default,
526
+ /** @deprecated Use `no-unnecessary-use-memo` instead */
527
+ "ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default,
523
528
  /** @deprecated Use `no-direct-set-state-in-use-effect` instead */
524
- "no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default,
525
- "prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default
529
+ "no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default
526
530
  };
527
531
 
528
532
  exports.meta = meta;
package/dist/index.mjs CHANGED
@@ -1,15 +1,15 @@
1
- import { useHookCollector, isReactHookCall, isUseCallbackCall, isReactHookCallWithNameLoose, isUseMemoCall, isReactHookCallWithNameAlias, isUseStateCall, isReactHookName } from '@eslint-react/core';
1
+ import { traverseUpGuard, isFunction, getNestedIdentifiers, toReadableNodeName, is, getNestedCallExpressions, isFunctionOfImmediatelyInvoked } from '@eslint-react/ast';
2
+ import { isReactHookCallWithNameAlias, useHookCollector, isReactHookCall, isUseCallbackCall, isReactHookCallWithNameLoose, isUseMemoCall, isUseStateCall, isReactHookName } from '@eslint-react/core';
2
3
  import { createRuleForPlugin, decodeSettings } from '@eslint-react/shared';
3
- import { isFunction, is, traverseUpGuard, getNestedIdentifiers, toReadableNodeName, getNestedCallExpressions, isFunctionOfImmediatelyInvoked } from '@eslint-react/ast';
4
- import { F, O, MutRef } from '@eslint-react/tools';
4
+ import { MutRef, O, F } from '@eslint-react/tools';
5
5
  import { findVariable, getVariableNode } from '@eslint-react/var';
6
6
  import { AST_NODE_TYPES } from '@typescript-eslint/types';
7
- import { getStaticValue } from '@typescript-eslint/utils/ast-utils';
8
7
  import { match, isMatching } from 'ts-pattern';
8
+ import { getStaticValue } from '@typescript-eslint/utils/ast-utils';
9
9
 
10
10
  // package.json
11
11
  var name = "eslint-plugin-react-hooks-extra";
12
- var version = "1.12.5-next.5";
12
+ var version = "1.13.0-beta.0";
13
13
  var createRule = createRuleForPlugin("hooks-extra");
14
14
  function isFromHookCall(name2, context, settings, predicate = F.constTrue) {
15
15
  const hookAlias = settings.additionalHooks?.[name2] ?? [];
@@ -90,201 +90,8 @@ function isVariableDeclaratorFromHookCall(node) {
90
90
  }
91
91
  }
92
92
 
93
- // src/rules/ensure-custom-hooks-using-other-hooks.ts
94
- var RULE_NAME = "ensure-custom-hooks-using-other-hooks";
95
- var ensure_custom_hooks_using_other_hooks_default = createRule({
96
- meta: {
97
- type: "problem",
98
- docs: {
99
- description: "enforce custom hooks using other hooks"
100
- },
101
- messages: {
102
- ensureCustomHooksUsingOtherHooks: "A custom hook '{{name}}' should use other hooks."
103
- },
104
- schema: []
105
- },
106
- name: RULE_NAME,
107
- create(context) {
108
- if (!context.sourceCode.text.includes("use")) return {};
109
- const { ctx, listeners } = useHookCollector();
110
- return {
111
- ...listeners,
112
- "Program:exit"(node) {
113
- const allHooks = ctx.getAllHooks(node);
114
- for (const { name: name2, node: node2, hookCalls } of allHooks.values()) {
115
- if (hookCalls.length > 0) continue;
116
- context.report({
117
- messageId: "ensureCustomHooksUsingOtherHooks",
118
- node: node2,
119
- data: {
120
- name: name2.value
121
- }
122
- });
123
- }
124
- }
125
- };
126
- },
127
- defaultOptions: []
128
- });
129
- var RULE_NAME2 = "ensure-use-callback-has-non-empty-deps";
130
- var ensure_use_callback_has_non_empty_deps_default = createRule({
131
- meta: {
132
- type: "problem",
133
- docs: {
134
- description: "enforce 'useCallback' has non-empty dependencies array"
135
- },
136
- messages: {
137
- ensureUseCallbackHasNonEmptyDeps: "An 'useCallback' should have a non-empty dependencies array."
138
- },
139
- schema: []
140
- },
141
- name: RULE_NAME2,
142
- create(context) {
143
- if (!context.sourceCode.text.includes("use")) return {};
144
- const alias = decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
145
- return {
146
- CallExpression(node) {
147
- if (!isReactHookCall(node)) return;
148
- const initialScope = context.sourceCode.getScope(node);
149
- if (!isUseCallbackCall(node, context) && !alias.some(isReactHookCallWithNameLoose(node))) {
150
- return;
151
- }
152
- const scope = context.sourceCode.getScope(node);
153
- const component = scope.block;
154
- if (!isFunction(component)) return;
155
- const [cb, deps] = node.arguments;
156
- if (!deps) {
157
- context.report({
158
- messageId: "ensureUseCallbackHasNonEmptyDeps",
159
- node
160
- });
161
- return;
162
- }
163
- const hasEmptyDeps = F.pipe(
164
- match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
165
- return F.pipe(
166
- findVariable(n.name, initialScope),
167
- O.flatMap(getVariableNode(0)),
168
- O.filter(is(AST_NODE_TYPES.ArrayExpression))
169
- );
170
- }).otherwise(O.none),
171
- O.exists((x) => x.elements.length === 0)
172
- );
173
- if (!hasEmptyDeps) return;
174
- if (!cb) {
175
- context.report({
176
- messageId: "ensureUseCallbackHasNonEmptyDeps",
177
- node
178
- });
179
- return;
180
- }
181
- const isReferencedToComponentScope = F.pipe(
182
- match(cb).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
183
- if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
184
- return O.some(n.body);
185
- }
186
- return O.some(n);
187
- }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
188
- return F.pipe(
189
- findVariable(n.name, initialScope),
190
- O.flatMap(getVariableNode(0)),
191
- O.filter(isFunction)
192
- );
193
- }).otherwise(O.none),
194
- O.map((n) => context.sourceCode.getScope(n)),
195
- O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
196
- O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
197
- );
198
- if (isReferencedToComponentScope) return;
199
- context.report({
200
- messageId: "ensureUseCallbackHasNonEmptyDeps",
201
- node
202
- });
203
- }
204
- };
205
- },
206
- defaultOptions: []
207
- });
208
- var RULE_NAME3 = "ensure-use-memo-has-non-empty-deps";
209
- var ensure_use_memo_has_non_empty_deps_default = createRule({
210
- meta: {
211
- type: "problem",
212
- docs: {
213
- description: "enforce 'useMemo' has non-empty dependencies array"
214
- },
215
- messages: {
216
- ensureUseMemoHasNonEmptyDeps: "An 'useMemo' should have a non-empty dependencies array."
217
- },
218
- schema: []
219
- },
220
- name: RULE_NAME3,
221
- create(context) {
222
- if (!context.sourceCode.text.includes("use")) return {};
223
- const alias = decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
224
- return {
225
- CallExpression(node) {
226
- if (!isReactHookCall(node)) return;
227
- const initialScope = context.sourceCode.getScope(node);
228
- if (!isUseMemoCall(node, context) && !alias.some(isReactHookCallWithNameLoose(node))) {
229
- return;
230
- }
231
- const scope = context.sourceCode.getScope(node);
232
- const component = scope.block;
233
- if (!isFunction(component)) return;
234
- const [cb, deps] = node.arguments;
235
- if (!deps) {
236
- context.report({
237
- messageId: "ensureUseMemoHasNonEmptyDeps",
238
- node
239
- });
240
- return;
241
- }
242
- const hasEmptyDeps = F.pipe(
243
- match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
244
- return F.pipe(
245
- findVariable(n.name, initialScope),
246
- O.flatMap(getVariableNode(0)),
247
- O.filter(is(AST_NODE_TYPES.ArrayExpression))
248
- );
249
- }).otherwise(O.none),
250
- O.exists((x) => x.elements.length === 0)
251
- );
252
- if (!hasEmptyDeps) return;
253
- if (!cb) {
254
- context.report({
255
- messageId: "ensureUseMemoHasNonEmptyDeps",
256
- node
257
- });
258
- return;
259
- }
260
- const isReferencedToComponentScope = F.pipe(
261
- match(cb).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
262
- if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
263
- return O.some(n.body);
264
- }
265
- return O.some(n);
266
- }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
267
- return F.pipe(
268
- findVariable(n.name, initialScope),
269
- O.flatMap(getVariableNode(0)),
270
- O.filter(isFunction)
271
- );
272
- }).otherwise(O.none),
273
- O.map((n) => context.sourceCode.getScope(n)),
274
- O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
275
- O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
276
- );
277
- if (isReferencedToComponentScope) return;
278
- context.report({
279
- messageId: "ensureUseMemoHasNonEmptyDeps",
280
- node
281
- });
282
- }
283
- };
284
- },
285
- defaultOptions: []
286
- });
287
- var RULE_NAME4 = "no-direct-set-state-in-use-effect";
93
+ // src/rules/no-direct-set-state-in-use-effect.ts
94
+ var RULE_NAME = "no-direct-set-state-in-use-effect";
288
95
  var no_direct_set_state_in_use_effect_default = createRule({
289
96
  meta: {
290
97
  type: "problem",
@@ -296,7 +103,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
296
103
  },
297
104
  schema: []
298
105
  },
299
- name: RULE_NAME4,
106
+ name: RULE_NAME,
300
107
  create(context) {
301
108
  if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
302
109
  const settings = decodeSettings(context.settings);
@@ -470,6 +277,198 @@ var no_direct_set_state_in_use_effect_default = createRule({
470
277
  },
471
278
  defaultOptions: []
472
279
  });
280
+ var RULE_NAME2 = "no-redundant-custom-hook";
281
+ var no_redundant_custom_hook_default = createRule({
282
+ meta: {
283
+ type: "problem",
284
+ docs: {
285
+ description: "enforce custom hooks to use at least one other hook inside"
286
+ },
287
+ messages: {
288
+ noRedundantCustomHook: "A custom hook '{{name}}' should use at least one other hook."
289
+ },
290
+ schema: []
291
+ },
292
+ name: RULE_NAME2,
293
+ create(context) {
294
+ const { ctx, listeners } = useHookCollector();
295
+ return {
296
+ ...listeners,
297
+ "Program:exit"(node) {
298
+ const allHooks = ctx.getAllHooks(node);
299
+ for (const { name: name2, node: node2, hookCalls } of allHooks.values()) {
300
+ if (hookCalls.length > 0) continue;
301
+ context.report({
302
+ messageId: "noRedundantCustomHook",
303
+ node: node2,
304
+ data: {
305
+ name: name2.value
306
+ }
307
+ });
308
+ }
309
+ }
310
+ };
311
+ },
312
+ defaultOptions: []
313
+ });
314
+ var RULE_NAME3 = "no-unnecessary-use-callback";
315
+ var no_unnecessary_use_callback_default = createRule({
316
+ meta: {
317
+ type: "problem",
318
+ docs: {
319
+ description: "disallow unnecessary usage of 'useCallback'"
320
+ },
321
+ messages: {
322
+ noUnnecessaryUseCallback: "An 'useCallback' with empty deps and no references to the component scope may be unnecessary."
323
+ },
324
+ schema: []
325
+ },
326
+ name: RULE_NAME3,
327
+ create(context) {
328
+ if (!context.sourceCode.text.includes("use")) return {};
329
+ const alias = decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
330
+ return {
331
+ CallExpression(node) {
332
+ if (!isReactHookCall(node)) return;
333
+ const initialScope = context.sourceCode.getScope(node);
334
+ if (!isUseCallbackCall(node, context) && !alias.some(isReactHookCallWithNameLoose(node))) {
335
+ return;
336
+ }
337
+ const scope = context.sourceCode.getScope(node);
338
+ const component = scope.block;
339
+ if (!isFunction(component)) return;
340
+ const [cb, deps] = node.arguments;
341
+ if (!deps) {
342
+ context.report({
343
+ messageId: "noUnnecessaryUseCallback",
344
+ node
345
+ });
346
+ return;
347
+ }
348
+ const hasEmptyDeps = F.pipe(
349
+ match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
350
+ return F.pipe(
351
+ findVariable(n.name, initialScope),
352
+ O.flatMap(getVariableNode(0)),
353
+ O.filter(is(AST_NODE_TYPES.ArrayExpression))
354
+ );
355
+ }).otherwise(O.none),
356
+ O.exists((x) => x.elements.length === 0)
357
+ );
358
+ if (!hasEmptyDeps) return;
359
+ if (!cb) {
360
+ context.report({
361
+ messageId: "noUnnecessaryUseCallback",
362
+ node
363
+ });
364
+ return;
365
+ }
366
+ const isReferencedToComponentScope = F.pipe(
367
+ match(cb).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
368
+ if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
369
+ return O.some(n.body);
370
+ }
371
+ return O.some(n);
372
+ }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
373
+ return F.pipe(
374
+ findVariable(n.name, initialScope),
375
+ O.flatMap(getVariableNode(0)),
376
+ O.filter(isFunction)
377
+ );
378
+ }).otherwise(O.none),
379
+ O.map((n) => context.sourceCode.getScope(n)),
380
+ O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
381
+ O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
382
+ );
383
+ if (isReferencedToComponentScope) return;
384
+ context.report({
385
+ messageId: "noUnnecessaryUseCallback",
386
+ node
387
+ });
388
+ }
389
+ };
390
+ },
391
+ defaultOptions: []
392
+ });
393
+ var RULE_NAME4 = "no-unnecessary-use-memo";
394
+ var no_unnecessary_use_memo_default = createRule({
395
+ meta: {
396
+ type: "problem",
397
+ docs: {
398
+ description: "disallow unnecessary usage of 'useMemo'"
399
+ },
400
+ messages: {
401
+ noUnnecessaryUseMemo: "An 'useMemo' with empty deps and no references to the component scope may be unnecessary."
402
+ },
403
+ schema: []
404
+ },
405
+ name: RULE_NAME4,
406
+ create(context) {
407
+ if (!context.sourceCode.text.includes("use")) return {};
408
+ const alias = decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
409
+ return {
410
+ CallExpression(node) {
411
+ if (!isReactHookCall(node)) return;
412
+ const initialScope = context.sourceCode.getScope(node);
413
+ if (!isUseMemoCall(node, context) && !alias.some(isReactHookCallWithNameLoose(node))) {
414
+ return;
415
+ }
416
+ const scope = context.sourceCode.getScope(node);
417
+ const component = scope.block;
418
+ if (!isFunction(component)) return;
419
+ const [cb, deps] = node.arguments;
420
+ if (!deps) {
421
+ context.report({
422
+ messageId: "noUnnecessaryUseMemo",
423
+ node
424
+ });
425
+ return;
426
+ }
427
+ const hasEmptyDeps = F.pipe(
428
+ match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
429
+ return F.pipe(
430
+ findVariable(n.name, initialScope),
431
+ O.flatMap(getVariableNode(0)),
432
+ O.filter(is(AST_NODE_TYPES.ArrayExpression))
433
+ );
434
+ }).otherwise(O.none),
435
+ O.exists((x) => x.elements.length === 0)
436
+ );
437
+ if (!hasEmptyDeps) return;
438
+ if (!cb) {
439
+ context.report({
440
+ messageId: "noUnnecessaryUseMemo",
441
+ node
442
+ });
443
+ return;
444
+ }
445
+ const isReferencedToComponentScope = F.pipe(
446
+ match(cb).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
447
+ if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
448
+ return O.some(n.body);
449
+ }
450
+ return O.some(n);
451
+ }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
452
+ return F.pipe(
453
+ findVariable(n.name, initialScope),
454
+ O.flatMap(getVariableNode(0)),
455
+ O.filter(isFunction)
456
+ );
457
+ }).otherwise(O.none),
458
+ O.map((n) => context.sourceCode.getScope(n)),
459
+ O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
460
+ O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
461
+ );
462
+ if (isReferencedToComponentScope) return;
463
+ context.report({
464
+ messageId: "noUnnecessaryUseMemo",
465
+ node
466
+ });
467
+ }
468
+ };
469
+ },
470
+ defaultOptions: []
471
+ });
473
472
  var RULE_NAME5 = "prefer-use-state-lazy-initialization";
474
473
  var ALLOW_LIST = ["Boolean", "String", "Number"];
475
474
  var prefer_use_state_lazy_initialization_default = createRule({
@@ -514,13 +513,18 @@ var meta = {
514
513
  version
515
514
  };
516
515
  var rules = {
517
- "ensure-custom-hooks-using-other-hooks": ensure_custom_hooks_using_other_hooks_default,
518
- "ensure-use-callback-has-non-empty-deps": ensure_use_callback_has_non_empty_deps_default,
519
- "ensure-use-memo-has-non-empty-deps": ensure_use_memo_has_non_empty_deps_default,
520
516
  "no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
517
+ "no-redundant-custom-hook": no_redundant_custom_hook_default,
518
+ "no-unnecessary-use-callback": no_unnecessary_use_callback_default,
519
+ "no-unnecessary-use-memo": no_unnecessary_use_memo_default,
520
+ "prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default,
521
+ // Deprecated Rules
522
+ /** @deprecated Use `no-redundant-custom-hook` instead */
523
+ "ensure-custom-hooks-using-other-hooks": no_redundant_custom_hook_default,
524
+ /** @deprecated Use `no-unnecessary-use-memo` instead */
525
+ "ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default,
521
526
  /** @deprecated Use `no-direct-set-state-in-use-effect` instead */
522
- "no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default,
523
- "prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default
527
+ "no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default
524
528
  };
525
529
 
526
530
  export { meta, rules };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks-extra",
3
- "version": "1.12.5-next.5",
3
+ "version": "1.13.0-beta.0",
4
4
  "description": "ESLint React's ESLint plugin for React Hooks related rules.",
5
5
  "keywords": [
6
6
  "eslint",
@@ -41,18 +41,18 @@
41
41
  "./package.json"
42
42
  ],
43
43
  "dependencies": {
44
- "@typescript-eslint/scope-manager": "^8.3.0",
45
- "@typescript-eslint/type-utils": "^8.3.0",
46
- "@typescript-eslint/types": "^8.3.0",
47
- "@typescript-eslint/utils": "^8.3.0",
44
+ "@typescript-eslint/scope-manager": "^8.4.0",
45
+ "@typescript-eslint/type-utils": "^8.4.0",
46
+ "@typescript-eslint/types": "^8.4.0",
47
+ "@typescript-eslint/utils": "^8.4.0",
48
48
  "ts-pattern": "^5.3.1",
49
- "@eslint-react/ast": "1.12.5-next.5",
50
- "@eslint-react/core": "1.12.5-next.5",
51
- "@eslint-react/shared": "1.12.5-next.5",
52
- "@eslint-react/jsx": "1.12.5-next.5",
53
- "@eslint-react/types": "1.12.5-next.5",
54
- "@eslint-react/tools": "1.12.5-next.5",
55
- "@eslint-react/var": "1.12.5-next.5"
49
+ "@eslint-react/core": "1.13.0-beta.0",
50
+ "@eslint-react/shared": "1.13.0-beta.0",
51
+ "@eslint-react/jsx": "1.13.0-beta.0",
52
+ "@eslint-react/tools": "1.13.0-beta.0",
53
+ "@eslint-react/var": "1.13.0-beta.0",
54
+ "@eslint-react/ast": "1.13.0-beta.0",
55
+ "@eslint-react/types": "1.13.0-beta.0"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/react": "^18.3.5",