eslint-plugin-react-hooks-extra 1.12.5-next.6 → 1.13.0-beta.1

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.6";
14
+ var version = "1.13.0-beta.1";
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,199 @@ 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 (ast.isEmptyFunction(node2)) continue;
303
+ if (hookCalls.length > 0) continue;
304
+ context.report({
305
+ messageId: "noRedundantCustomHook",
306
+ node: node2,
307
+ data: {
308
+ name: name2.value
309
+ }
310
+ });
311
+ }
312
+ }
313
+ };
314
+ },
315
+ defaultOptions: []
316
+ });
317
+ var RULE_NAME3 = "no-unnecessary-use-callback";
318
+ var no_unnecessary_use_callback_default = createRule({
319
+ meta: {
320
+ type: "problem",
321
+ docs: {
322
+ description: "disallow unnecessary usage of 'useCallback'"
323
+ },
324
+ messages: {
325
+ noUnnecessaryUseCallback: "An 'useCallback' with empty deps and no references to the component scope may be unnecessary."
326
+ },
327
+ schema: []
328
+ },
329
+ name: RULE_NAME3,
330
+ create(context) {
331
+ if (!context.sourceCode.text.includes("use")) return {};
332
+ const alias = shared.decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
333
+ return {
334
+ CallExpression(node) {
335
+ if (!core.isReactHookCall(node)) return;
336
+ const initialScope = context.sourceCode.getScope(node);
337
+ if (!core.isUseCallbackCall(node, context) && !alias.some(core.isReactHookCallWithNameLoose(node))) {
338
+ return;
339
+ }
340
+ const scope = context.sourceCode.getScope(node);
341
+ const component = scope.block;
342
+ if (!ast.isFunction(component)) return;
343
+ const [cb, deps] = node.arguments;
344
+ if (!deps) {
345
+ context.report({
346
+ messageId: "noUnnecessaryUseCallback",
347
+ node
348
+ });
349
+ return;
350
+ }
351
+ const hasEmptyDeps = tools.F.pipe(
352
+ tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
353
+ return tools.F.pipe(
354
+ _var.findVariable(n.name, initialScope),
355
+ tools.O.flatMap(_var.getVariableNode(0)),
356
+ tools.O.filter(ast.is(types.AST_NODE_TYPES.ArrayExpression))
357
+ );
358
+ }).otherwise(tools.O.none),
359
+ tools.O.exists((x) => x.elements.length === 0)
360
+ );
361
+ if (!hasEmptyDeps) return;
362
+ if (!cb) {
363
+ context.report({
364
+ messageId: "noUnnecessaryUseCallback",
365
+ node
366
+ });
367
+ return;
368
+ }
369
+ const isReferencedToComponentScope = tools.F.pipe(
370
+ tsPattern.match(cb).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
371
+ if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
372
+ return tools.O.some(n.body);
373
+ }
374
+ return tools.O.some(n);
375
+ }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
376
+ return tools.F.pipe(
377
+ _var.findVariable(n.name, initialScope),
378
+ tools.O.flatMap(_var.getVariableNode(0)),
379
+ tools.O.filter(ast.isFunction)
380
+ );
381
+ }).otherwise(tools.O.none),
382
+ tools.O.map((n) => context.sourceCode.getScope(n)),
383
+ tools.O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
384
+ tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
385
+ );
386
+ if (isReferencedToComponentScope) return;
387
+ context.report({
388
+ messageId: "noUnnecessaryUseCallback",
389
+ node
390
+ });
391
+ }
392
+ };
393
+ },
394
+ defaultOptions: []
395
+ });
396
+ var RULE_NAME4 = "no-unnecessary-use-memo";
397
+ var no_unnecessary_use_memo_default = createRule({
398
+ meta: {
399
+ type: "problem",
400
+ docs: {
401
+ description: "disallow unnecessary usage of 'useMemo'"
402
+ },
403
+ messages: {
404
+ noUnnecessaryUseMemo: "An 'useMemo' with empty deps and no references to the component scope may be unnecessary."
405
+ },
406
+ schema: []
407
+ },
408
+ name: RULE_NAME4,
409
+ create(context) {
410
+ if (!context.sourceCode.text.includes("use")) return {};
411
+ const alias = shared.decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
412
+ return {
413
+ CallExpression(node) {
414
+ if (!core.isReactHookCall(node)) return;
415
+ const initialScope = context.sourceCode.getScope(node);
416
+ if (!core.isUseMemoCall(node, context) && !alias.some(core.isReactHookCallWithNameLoose(node))) {
417
+ return;
418
+ }
419
+ const scope = context.sourceCode.getScope(node);
420
+ const component = scope.block;
421
+ if (!ast.isFunction(component)) return;
422
+ const [cb, deps] = node.arguments;
423
+ if (!deps) {
424
+ context.report({
425
+ messageId: "noUnnecessaryUseMemo",
426
+ node
427
+ });
428
+ return;
429
+ }
430
+ const hasEmptyDeps = tools.F.pipe(
431
+ tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
432
+ return tools.F.pipe(
433
+ _var.findVariable(n.name, initialScope),
434
+ tools.O.flatMap(_var.getVariableNode(0)),
435
+ tools.O.filter(ast.is(types.AST_NODE_TYPES.ArrayExpression))
436
+ );
437
+ }).otherwise(tools.O.none),
438
+ tools.O.exists((x) => x.elements.length === 0)
439
+ );
440
+ if (!hasEmptyDeps) return;
441
+ if (!cb) {
442
+ context.report({
443
+ messageId: "noUnnecessaryUseMemo",
444
+ node
445
+ });
446
+ return;
447
+ }
448
+ const isReferencedToComponentScope = tools.F.pipe(
449
+ tsPattern.match(cb).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
450
+ if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
451
+ return tools.O.some(n.body);
452
+ }
453
+ return tools.O.some(n);
454
+ }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
455
+ return tools.F.pipe(
456
+ _var.findVariable(n.name, initialScope),
457
+ tools.O.flatMap(_var.getVariableNode(0)),
458
+ tools.O.filter(ast.isFunction)
459
+ );
460
+ }).otherwise(tools.O.none),
461
+ tools.O.map((n) => context.sourceCode.getScope(n)),
462
+ tools.O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
463
+ tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
464
+ );
465
+ if (isReferencedToComponentScope) return;
466
+ context.report({
467
+ messageId: "noUnnecessaryUseMemo",
468
+ node
469
+ });
470
+ }
471
+ };
472
+ },
473
+ defaultOptions: []
474
+ });
475
475
  var RULE_NAME5 = "prefer-use-state-lazy-initialization";
476
476
  var ALLOW_LIST = ["Boolean", "String", "Number"];
477
477
  var prefer_use_state_lazy_initialization_default = createRule({
@@ -516,13 +516,18 @@ var meta = {
516
516
  version
517
517
  };
518
518
  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
519
  "no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
520
+ "no-redundant-custom-hook": no_redundant_custom_hook_default,
521
+ "no-unnecessary-use-callback": no_unnecessary_use_callback_default,
522
+ "no-unnecessary-use-memo": no_unnecessary_use_memo_default,
523
+ "prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default,
524
+ // Deprecated Rules
525
+ /** @deprecated Use `no-redundant-custom-hook` instead */
526
+ "ensure-custom-hooks-using-other-hooks": no_redundant_custom_hook_default,
527
+ /** @deprecated Use `no-unnecessary-use-memo` instead */
528
+ "ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default,
523
529
  /** @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
530
+ "no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default
526
531
  };
527
532
 
528
533
  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, isEmptyFunction, 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.6";
12
+ var version = "1.13.0-beta.1";
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,199 @@ 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 (isEmptyFunction(node2)) continue;
301
+ if (hookCalls.length > 0) continue;
302
+ context.report({
303
+ messageId: "noRedundantCustomHook",
304
+ node: node2,
305
+ data: {
306
+ name: name2.value
307
+ }
308
+ });
309
+ }
310
+ }
311
+ };
312
+ },
313
+ defaultOptions: []
314
+ });
315
+ var RULE_NAME3 = "no-unnecessary-use-callback";
316
+ var no_unnecessary_use_callback_default = createRule({
317
+ meta: {
318
+ type: "problem",
319
+ docs: {
320
+ description: "disallow unnecessary usage of 'useCallback'"
321
+ },
322
+ messages: {
323
+ noUnnecessaryUseCallback: "An 'useCallback' with empty deps and no references to the component scope may be unnecessary."
324
+ },
325
+ schema: []
326
+ },
327
+ name: RULE_NAME3,
328
+ create(context) {
329
+ if (!context.sourceCode.text.includes("use")) return {};
330
+ const alias = decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
331
+ return {
332
+ CallExpression(node) {
333
+ if (!isReactHookCall(node)) return;
334
+ const initialScope = context.sourceCode.getScope(node);
335
+ if (!isUseCallbackCall(node, context) && !alias.some(isReactHookCallWithNameLoose(node))) {
336
+ return;
337
+ }
338
+ const scope = context.sourceCode.getScope(node);
339
+ const component = scope.block;
340
+ if (!isFunction(component)) return;
341
+ const [cb, deps] = node.arguments;
342
+ if (!deps) {
343
+ context.report({
344
+ messageId: "noUnnecessaryUseCallback",
345
+ node
346
+ });
347
+ return;
348
+ }
349
+ const hasEmptyDeps = F.pipe(
350
+ match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
351
+ return F.pipe(
352
+ findVariable(n.name, initialScope),
353
+ O.flatMap(getVariableNode(0)),
354
+ O.filter(is(AST_NODE_TYPES.ArrayExpression))
355
+ );
356
+ }).otherwise(O.none),
357
+ O.exists((x) => x.elements.length === 0)
358
+ );
359
+ if (!hasEmptyDeps) return;
360
+ if (!cb) {
361
+ context.report({
362
+ messageId: "noUnnecessaryUseCallback",
363
+ node
364
+ });
365
+ return;
366
+ }
367
+ const isReferencedToComponentScope = F.pipe(
368
+ match(cb).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
369
+ if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
370
+ return O.some(n.body);
371
+ }
372
+ return O.some(n);
373
+ }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
374
+ return F.pipe(
375
+ findVariable(n.name, initialScope),
376
+ O.flatMap(getVariableNode(0)),
377
+ O.filter(isFunction)
378
+ );
379
+ }).otherwise(O.none),
380
+ O.map((n) => context.sourceCode.getScope(n)),
381
+ O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
382
+ O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
383
+ );
384
+ if (isReferencedToComponentScope) return;
385
+ context.report({
386
+ messageId: "noUnnecessaryUseCallback",
387
+ node
388
+ });
389
+ }
390
+ };
391
+ },
392
+ defaultOptions: []
393
+ });
394
+ var RULE_NAME4 = "no-unnecessary-use-memo";
395
+ var no_unnecessary_use_memo_default = createRule({
396
+ meta: {
397
+ type: "problem",
398
+ docs: {
399
+ description: "disallow unnecessary usage of 'useMemo'"
400
+ },
401
+ messages: {
402
+ noUnnecessaryUseMemo: "An 'useMemo' with empty deps and no references to the component scope may be unnecessary."
403
+ },
404
+ schema: []
405
+ },
406
+ name: RULE_NAME4,
407
+ create(context) {
408
+ if (!context.sourceCode.text.includes("use")) return {};
409
+ const alias = decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
410
+ return {
411
+ CallExpression(node) {
412
+ if (!isReactHookCall(node)) return;
413
+ const initialScope = context.sourceCode.getScope(node);
414
+ if (!isUseMemoCall(node, context) && !alias.some(isReactHookCallWithNameLoose(node))) {
415
+ return;
416
+ }
417
+ const scope = context.sourceCode.getScope(node);
418
+ const component = scope.block;
419
+ if (!isFunction(component)) return;
420
+ const [cb, deps] = node.arguments;
421
+ if (!deps) {
422
+ context.report({
423
+ messageId: "noUnnecessaryUseMemo",
424
+ node
425
+ });
426
+ return;
427
+ }
428
+ const hasEmptyDeps = F.pipe(
429
+ match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
430
+ return F.pipe(
431
+ findVariable(n.name, initialScope),
432
+ O.flatMap(getVariableNode(0)),
433
+ O.filter(is(AST_NODE_TYPES.ArrayExpression))
434
+ );
435
+ }).otherwise(O.none),
436
+ O.exists((x) => x.elements.length === 0)
437
+ );
438
+ if (!hasEmptyDeps) return;
439
+ if (!cb) {
440
+ context.report({
441
+ messageId: "noUnnecessaryUseMemo",
442
+ node
443
+ });
444
+ return;
445
+ }
446
+ const isReferencedToComponentScope = F.pipe(
447
+ match(cb).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
448
+ if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
449
+ return O.some(n.body);
450
+ }
451
+ return O.some(n);
452
+ }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
453
+ return F.pipe(
454
+ findVariable(n.name, initialScope),
455
+ O.flatMap(getVariableNode(0)),
456
+ O.filter(isFunction)
457
+ );
458
+ }).otherwise(O.none),
459
+ O.map((n) => context.sourceCode.getScope(n)),
460
+ O.map((s) => [...s.childScopes, s].flatMap((x) => x.references)),
461
+ O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
462
+ );
463
+ if (isReferencedToComponentScope) return;
464
+ context.report({
465
+ messageId: "noUnnecessaryUseMemo",
466
+ node
467
+ });
468
+ }
469
+ };
470
+ },
471
+ defaultOptions: []
472
+ });
473
473
  var RULE_NAME5 = "prefer-use-state-lazy-initialization";
474
474
  var ALLOW_LIST = ["Boolean", "String", "Number"];
475
475
  var prefer_use_state_lazy_initialization_default = createRule({
@@ -514,13 +514,18 @@ var meta = {
514
514
  version
515
515
  };
516
516
  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
517
  "no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
518
+ "no-redundant-custom-hook": no_redundant_custom_hook_default,
519
+ "no-unnecessary-use-callback": no_unnecessary_use_callback_default,
520
+ "no-unnecessary-use-memo": no_unnecessary_use_memo_default,
521
+ "prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default,
522
+ // Deprecated Rules
523
+ /** @deprecated Use `no-redundant-custom-hook` instead */
524
+ "ensure-custom-hooks-using-other-hooks": no_redundant_custom_hook_default,
525
+ /** @deprecated Use `no-unnecessary-use-memo` instead */
526
+ "ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default,
521
527
  /** @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
528
+ "no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default
524
529
  };
525
530
 
526
531
  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.6",
3
+ "version": "1.13.0-beta.1",
4
4
  "description": "ESLint React's ESLint plugin for React Hooks related rules.",
5
5
  "keywords": [
6
6
  "eslint",
@@ -46,13 +46,13 @@
46
46
  "@typescript-eslint/types": "^8.4.0",
47
47
  "@typescript-eslint/utils": "^8.4.0",
48
48
  "ts-pattern": "^5.3.1",
49
- "@eslint-react/ast": "1.12.5-next.6",
50
- "@eslint-react/core": "1.12.5-next.6",
51
- "@eslint-react/jsx": "1.12.5-next.6",
52
- "@eslint-react/tools": "1.12.5-next.6",
53
- "@eslint-react/shared": "1.12.5-next.6",
54
- "@eslint-react/types": "1.12.5-next.6",
55
- "@eslint-react/var": "1.12.5-next.6"
49
+ "@eslint-react/ast": "1.13.0-beta.1",
50
+ "@eslint-react/core": "1.13.0-beta.1",
51
+ "@eslint-react/jsx": "1.13.0-beta.1",
52
+ "@eslint-react/tools": "1.13.0-beta.1",
53
+ "@eslint-react/shared": "1.13.0-beta.1",
54
+ "@eslint-react/var": "1.13.0-beta.1",
55
+ "@eslint-react/types": "1.13.0-beta.1"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/react": "^18.3.5",