eslint-plugin-react-hooks-extra 1.8.2 → 1.8.3-next.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
@@ -41,7 +41,7 @@ export default [
41
41
 
42
42
  ## Rules
43
43
 
44
- | Rule | Description | 💼 | 💭 | 🪧 |
44
+ | Rule | Description | 💼 | 💭 | |
45
45
  | :----------------------------------------- | :------------------------------------------------------------------------------ | :-: | :-: | :-: |
46
46
  | `ensure-custom-hooks-using-other-hooks` | Warns when custom Hooks that don't use other Hooks. | ✔️ | | |
47
47
  | `ensure-use-callback-has-non-empty-deps` | Warns when `useCallback` is called with empty dependencies array. | 🧐 | | |
package/dist/index.d.mts CHANGED
@@ -5,12 +5,12 @@ 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<"ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
9
- readonly "ensure-use-callback-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
10
- readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
11
- readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_EFFECT", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
- readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
13
- readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"PREFER_USE_STATE_LAZY_INITIALIZATION", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
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
+ readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
+ readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseLayoutEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
13
+ readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"preferUseStateLazyInitialization", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
14
14
  };
15
15
 
16
16
  export { meta, rules };
package/dist/index.d.ts CHANGED
@@ -5,12 +5,12 @@ 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<"ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
9
- readonly "ensure-use-callback-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
10
- readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
11
- readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_EFFECT", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
- readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
13
- readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"PREFER_USE_STATE_LAZY_INITIALIZATION", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
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
+ readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
12
+ readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseLayoutEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
13
+ readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"preferUseStateLazyInitialization", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
14
14
  };
15
15
 
16
16
  export { meta, rules };
package/dist/index.js CHANGED
@@ -30,21 +30,24 @@ var R__namespace = /*#__PURE__*/_interopNamespace(R);
30
30
 
31
31
  // package.json
32
32
  var name = "eslint-plugin-react-hooks-extra";
33
- var version = "1.8.2";
33
+ var version = "1.8.3-next.1";
34
34
  var createRule = shared.createRuleForPlugin("hooks-extra");
35
- function isFromUseStateCall(context, useStateAlias) {
36
- return (topLevelId) => {
37
- const useStateCall = tools.F.pipe(
38
- _var.findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
39
- tools.O.flatMap(_var.getVariableNode(0)),
40
- tools.O.filter(ast.is(ast.NodeType.CallExpression)),
41
- tools.O.filter(core.isReactHookCallWithNameAlias("useState", context, useStateAlias))
42
- );
43
- if (tools.O.isNone(useStateCall)) return false;
44
- const { parent } = useStateCall.value;
35
+ function isFromHookCall(name2, context, settings, predicate = tools.F.constTrue) {
36
+ const hookAlias = settings.additionalHooks?.[name2] ?? [];
37
+ return (topLevelId) => tools.F.pipe(
38
+ _var.findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
39
+ tools.O.flatMap(_var.getVariableNode(0)),
40
+ tools.O.filter(ast.is(ast.NodeType.CallExpression)),
41
+ tools.O.filter(core.isReactHookCallWithNameAlias(name2, context, hookAlias)),
42
+ tools.O.exists((call) => predicate(topLevelId, call))
43
+ );
44
+ }
45
+ function isFromUseStateCall(context, settings) {
46
+ return (toplevelId) => isFromHookCall("useState", context, settings, (topLevelId, call) => {
47
+ const { parent } = call;
45
48
  if (!("id" in parent && parent.id?.type === ast.NodeType.ArrayPattern)) return true;
46
49
  return parent.id.elements.findIndex((e2) => e2?.type === ast.NodeType.Identifier && e2.name === topLevelId.name) === 1;
47
- };
50
+ })(toplevelId);
48
51
  }
49
52
 
50
53
  // ../../../node_modules/.pnpm/ts-pattern@5.2.0/node_modules/ts-pattern/dist/index.js
@@ -230,18 +233,19 @@ var z = class _z {
230
233
  }
231
234
  };
232
235
 
233
- // src/utils/is-set-state-call.ts
234
- function isSetStateCall(context, useStateAlias) {
236
+ // src/utils/is-set-function-call.ts
237
+ function isSetFunctionCall(context, settings) {
238
+ const isIdFromUseStateCall = isFromUseStateCall(context, settings);
235
239
  return (node) => {
236
240
  switch (node.callee.type) {
237
241
  case ast.NodeType.Identifier: {
238
- return isFromUseStateCall(context, useStateAlias)(node.callee);
242
+ return isIdFromUseStateCall(node.callee);
239
243
  }
240
244
  case ast.NodeType.MemberExpression: {
241
245
  if (!("name" in node.callee.object)) return false;
242
246
  const initialScope = context.sourceCode.getScope(node);
243
247
  const property = astUtils.getStaticValue(node.callee.property, initialScope);
244
- if (property?.value === 1) return isFromUseStateCall(context, useStateAlias)(node.callee.object);
248
+ if (property?.value === 1) return isIdFromUseStateCall(node.callee.object);
245
249
  return false;
246
250
  }
247
251
  case ast.NodeType.CallExpression: {
@@ -259,7 +263,7 @@ function isSetStateCall(context, useStateAlias) {
259
263
  if (!isAt || !index) return false;
260
264
  const initialScope = context.sourceCode.getScope(node);
261
265
  const value = astUtils.getStaticValue(index, initialScope);
262
- if (value?.value === 1) return isFromUseStateCall(context, useStateAlias)(callee.object);
266
+ if (value?.value === 1) return isIdFromUseStateCall(callee.object);
263
267
  return false;
264
268
  }
265
269
  default: {
@@ -294,7 +298,7 @@ var ensure_custom_hooks_using_other_hooks_default = createRule({
294
298
  description: "enforce custom hooks using other hooks"
295
299
  },
296
300
  messages: {
297
- ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS: "A custom hook '{{name}}' should use other hooks."
301
+ ensureCustomHooksUsingOtherHooks: "A custom hook '{{name}}' should use other hooks."
298
302
  },
299
303
  schema: []
300
304
  },
@@ -311,7 +315,7 @@ var ensure_custom_hooks_using_other_hooks_default = createRule({
311
315
  data: {
312
316
  name: name2.value
313
317
  },
314
- messageId: "ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS",
318
+ messageId: "ensureCustomHooksUsingOtherHooks",
315
319
  node: node2
316
320
  });
317
321
  }
@@ -328,7 +332,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
328
332
  description: "enforce 'useCallback' has non-empty dependencies array"
329
333
  },
330
334
  messages: {
331
- ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS: "An 'useCallback' should have a non-empty dependencies array."
335
+ ensureUseCallbackHasNonEmptyDeps: "An 'useCallback' should have a non-empty dependencies array."
332
336
  },
333
337
  schema: []
334
338
  },
@@ -348,7 +352,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
348
352
  const [cb, deps] = node.arguments;
349
353
  if (!deps) {
350
354
  context.report({
351
- messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
355
+ messageId: "ensureUseCallbackHasNonEmptyDeps",
352
356
  node
353
357
  });
354
358
  return;
@@ -366,7 +370,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
366
370
  if (!hasEmptyDeps) return;
367
371
  if (!cb) {
368
372
  context.report({
369
- messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
373
+ messageId: "ensureUseCallbackHasNonEmptyDeps",
370
374
  node
371
375
  });
372
376
  return;
@@ -390,7 +394,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
390
394
  );
391
395
  if (isReferencedToComponentScope) return;
392
396
  context.report({
393
- messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
397
+ messageId: "ensureUseCallbackHasNonEmptyDeps",
394
398
  node
395
399
  });
396
400
  }
@@ -406,7 +410,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
406
410
  description: "enforce 'useMemo' has non-empty dependencies array"
407
411
  },
408
412
  messages: {
409
- ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS: "An 'useMemo' should have a non-empty dependencies array."
413
+ ensureUseMemoHasNonEmptyDeps: "An 'useMemo' should have a non-empty dependencies array."
410
414
  },
411
415
  schema: []
412
416
  },
@@ -426,7 +430,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
426
430
  const [cb, deps] = node.arguments;
427
431
  if (!deps) {
428
432
  context.report({
429
- messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
433
+ messageId: "ensureUseMemoHasNonEmptyDeps",
430
434
  node
431
435
  });
432
436
  return;
@@ -444,7 +448,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
444
448
  if (!hasEmptyDeps) return;
445
449
  if (!cb) {
446
450
  context.report({
447
- messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
451
+ messageId: "ensureUseMemoHasNonEmptyDeps",
448
452
  node
449
453
  });
450
454
  return;
@@ -468,7 +472,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
468
472
  );
469
473
  if (isReferencedToComponentScope) return;
470
474
  context.report({
471
- messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
475
+ messageId: "ensureUseMemoHasNonEmptyDeps",
472
476
  node
473
477
  });
474
478
  }
@@ -477,16 +481,6 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
477
481
  defaultOptions: []
478
482
  });
479
483
  var RULE_NAME4 = "no-direct-set-state-in-use-effect";
480
- function isEffectFunction(context, useSomeEffectAlias) {
481
- return (node) => node.parent?.type === ast.NodeType.CallExpression && node.parent.callee !== node && core.isReactHookCallWithNameAlias("useEffect", context, useSomeEffectAlias)(node.parent);
482
- }
483
- function getCallKind(node, context, alias) {
484
- const [useStateAlias, useEffectAlias] = alias;
485
- return $(node).when(core.isReactHookCallWithNameAlias("useState", context, useStateAlias), () => "useState").when(core.isReactHookCallWithNameAlias("useEffect", context, useEffectAlias), () => "useEffect").when(isSetStateCall(context, useStateAlias), () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
486
- }
487
- function getFunctionKind(node, context, useEffectAlias) {
488
- return $(node).when(isEffectFunction(context, useEffectAlias), () => "effect").when(ast.isIIFE, () => "immediate").otherwise(() => "other");
489
- }
490
484
  var no_direct_set_state_in_use_effect_default = createRule({
491
485
  meta: {
492
486
  type: "problem",
@@ -494,14 +488,20 @@ var no_direct_set_state_in_use_effect_default = createRule({
494
488
  description: "disallow direct calls to the 'set' function of 'useState' in 'useEffect'"
495
489
  },
496
490
  messages: {
497
- NO_DIRECT_SET_STATE_IN_USE_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useEffect'."
491
+ noDirectSetStateInUseEffect: "Do not call the 'set' function of 'useState' directly in 'useEffect'."
498
492
  },
499
493
  schema: []
500
494
  },
501
495
  name: RULE_NAME4,
502
496
  create(context) {
503
497
  const settings = shared.decodeSettings(context.settings);
504
- const { useEffect: useEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
498
+ const additionalHooks = settings.additionalHooks ?? {};
499
+ const isUseEffectCall = core.isReactHookCallWithNameAlias("useEffect", context, additionalHooks.useEffect ?? []);
500
+ const isUseStateCall2 = core.isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
501
+ const isUseMemoCall2 = core.isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
502
+ const isUseCallbackCall2 = core.isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
503
+ const isSetStateCall = isSetFunctionCall(context, settings);
504
+ const isIdFromUseStateCall = isFromUseStateCall(context, settings);
505
505
  const functionStack = [];
506
506
  const effectFunctionRef = tools.MutRef.make(null);
507
507
  const effectFunctionIdentifiers = [];
@@ -516,9 +516,18 @@ var no_direct_set_state_in_use_effect_default = createRule({
516
516
  const onEffectFunctionExit = (node) => {
517
517
  tools.MutRef.update(effectFunctionRef, (current) => current === node ? null : current);
518
518
  };
519
+ function isEffectFunction(node) {
520
+ return node.parent?.type === ast.NodeType.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
521
+ }
522
+ function getCallKind(node) {
523
+ return $(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
524
+ }
525
+ function getFunctionKind(node) {
526
+ return $(node).when(isEffectFunction, () => "effect").when(ast.isIIFE, () => "immediate").otherwise(() => "other");
527
+ }
519
528
  return {
520
529
  ":function"(node) {
521
- const functionKind = getFunctionKind(node, context, useEffectAlias);
530
+ const functionKind = getFunctionKind(node);
522
531
  functionStack.push([node, functionKind]);
523
532
  $(functionKind).with("effect", () => {
524
533
  onEffectFunctionEnter(node);
@@ -532,7 +541,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
532
541
  const effectFn = tools.MutRef.get(effectFunctionRef);
533
542
  const [parentFn, parentFnKind] = R__namespace.last(functionStack) ?? [];
534
543
  if (parentFn?.async) return;
535
- $(getCallKind(node, context, [useStateAlias, useEffectAlias])).with("setState", () => {
544
+ $(getCallKind(node)).with("setState", () => {
536
545
  if (!parentFn) return;
537
546
  if (parentFn !== effectFn && parentFnKind !== "immediate") {
538
547
  const maybeVd = ast.traverseUpGuard(node, isVariableDeclaratorFromHookCall);
@@ -547,7 +556,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
547
556
  return;
548
557
  }
549
558
  context.report({
550
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
559
+ messageId: "noDirectSetStateInUseEffect",
551
560
  node
552
561
  });
553
562
  }).with("useEffect", () => {
@@ -563,19 +572,20 @@ var no_direct_set_state_in_use_effect_default = createRule({
563
572
  },
564
573
  Identifier(node) {
565
574
  if (!node.parent) return;
566
- if (!isFromUseStateCall(context, useStateAlias)(node)) return;
575
+ if (node.parent.type === ast.NodeType.CallExpression && node.parent.callee === node) return;
576
+ if (!isIdFromUseStateCall(node)) return;
567
577
  switch (node.parent.type) {
568
578
  case ast.NodeType.CallExpression: {
569
579
  const [firstArg] = node.parent.arguments;
570
580
  if (node !== firstArg) break;
571
- if (core.isReactHookCallWithNameAlias("useCallback", context, useStateAlias)(node.parent)) {
581
+ if (isUseCallbackCall2(node.parent)) {
572
582
  const maybeVd = ast.traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
573
583
  if (tools.O.isNone(maybeVd)) break;
574
584
  const vd = maybeVd.value;
575
585
  const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
576
586
  indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
577
587
  }
578
- if (core.isReactHookCallWithNameAlias("useEffect", context, useEffectAlias)(node.parent)) {
588
+ if (isUseEffectCall(node.parent)) {
579
589
  const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
580
590
  indirectSetStateCallsAsEFs.set(node.parent, [...calls, node]);
581
591
  }
@@ -584,7 +594,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
584
594
  case ast.NodeType.ArrowFunctionExpression: {
585
595
  const parent = node.parent.parent;
586
596
  if (parent?.type !== ast.NodeType.CallExpression) break;
587
- if (!core.isReactHookCallWithNameAlias("useMemo", context, useStateAlias)(parent)) break;
597
+ if (!isUseMemoCall2(parent)) break;
588
598
  const maybeVd = ast.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
589
599
  if (tools.O.isNone(maybeVd)) break;
590
600
  const vd = maybeVd.value;
@@ -610,7 +620,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
610
620
  for (const call of calls) {
611
621
  context.report({
612
622
  data: { name: call.name },
613
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
623
+ messageId: "noDirectSetStateInUseEffect",
614
624
  node: call
615
625
  });
616
626
  }
@@ -622,7 +632,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
622
632
  for (const setStateCall of setStateCalls) {
623
633
  context.report({
624
634
  data: { name: name2 },
625
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
635
+ messageId: "noDirectSetStateInUseEffect",
626
636
  node: setStateCall
627
637
  });
628
638
  }
@@ -632,7 +642,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
632
642
  for (const setStateCall of setStateCalls) {
633
643
  context.report({
634
644
  data: { name: id.name },
635
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
645
+ messageId: "noDirectSetStateInUseEffect",
636
646
  node: setStateCall
637
647
  });
638
648
  }
@@ -643,16 +653,6 @@ var no_direct_set_state_in_use_effect_default = createRule({
643
653
  defaultOptions: []
644
654
  });
645
655
  var RULE_NAME5 = "no-direct-set-state-in-use-layout-effect";
646
- function isEffectFunction2(context, useSomeEffectAlias) {
647
- return (node) => node.parent?.type === ast.NodeType.CallExpression && node.parent.callee !== node && core.isReactHookCallWithNameAlias("useLayoutEffect", context, useSomeEffectAlias)(node.parent);
648
- }
649
- function getCallKind2(node, context, alias) {
650
- const [useStateAlias, useLayoutEffectAlias] = alias;
651
- return $(node).when(core.isReactHookCallWithNameAlias("useState", context, useStateAlias), () => "useState").when(core.isReactHookCallWithNameAlias("useLayoutEffect", context, useLayoutEffectAlias), () => "useLayoutEffect").when(isSetStateCall(context, useStateAlias), () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
652
- }
653
- function getFunctionKind2(node, context, useLayoutEffectAlias) {
654
- return $(node).when(isEffectFunction2(context, useLayoutEffectAlias), () => "effect").when(ast.isIIFE, () => "immediate").otherwise(() => "other");
655
- }
656
656
  var no_direct_set_state_in_use_layout_effect_default = createRule({
657
657
  meta: {
658
658
  type: "problem",
@@ -660,14 +660,24 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
660
660
  description: "disallow direct calls to the 'set' function of 'useState' in 'useLayoutEffect'"
661
661
  },
662
662
  messages: {
663
- NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useLayoutEffect'."
663
+ noDirectSetStateInUseLayoutEffect: "Do not call the 'set' function of 'useState' directly in 'useLayoutEffect'."
664
664
  },
665
665
  schema: []
666
666
  },
667
667
  name: RULE_NAME5,
668
668
  create(context) {
669
669
  const settings = shared.decodeSettings(context.settings);
670
- const { useLayoutEffect: useLayoutEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
670
+ const additionalHooks = settings.additionalHooks ?? {};
671
+ const isUseEffectCall = core.isReactHookCallWithNameAlias(
672
+ "useLayoutEffect",
673
+ context,
674
+ additionalHooks.useLayoutEffect ?? []
675
+ );
676
+ const isUseStateCall2 = core.isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
677
+ const isUseMemoCall2 = core.isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
678
+ const isUseCallbackCall2 = core.isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
679
+ const isSetStateCall = isSetFunctionCall(context, settings);
680
+ const isIdFromUseStateCall = isFromUseStateCall(context, settings);
671
681
  const functionStack = [];
672
682
  const effectFunctionRef = tools.MutRef.make(null);
673
683
  const effectFunctionIdentifiers = [];
@@ -682,9 +692,18 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
682
692
  const onEffectFunctionExit = (node) => {
683
693
  tools.MutRef.update(effectFunctionRef, (current) => current === node ? null : current);
684
694
  };
695
+ function isEffectFunction(node) {
696
+ return node.parent?.type === ast.NodeType.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
697
+ }
698
+ function getCallKind(node) {
699
+ return $(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
700
+ }
701
+ function getFunctionKind(node) {
702
+ return $(node).when(isEffectFunction, () => "effect").when(ast.isIIFE, () => "immediate").otherwise(() => "other");
703
+ }
685
704
  return {
686
705
  ":function"(node) {
687
- const functionKind = getFunctionKind2(node, context, useLayoutEffectAlias);
706
+ const functionKind = getFunctionKind(node);
688
707
  functionStack.push([node, functionKind]);
689
708
  $(functionKind).with("effect", () => {
690
709
  onEffectFunctionEnter(node);
@@ -698,7 +717,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
698
717
  const effectFn = tools.MutRef.get(effectFunctionRef);
699
718
  const [parentFn, parentFnKind] = R__namespace.last(functionStack) ?? [];
700
719
  if (parentFn?.async) return;
701
- $(getCallKind2(node, context, [useStateAlias, useLayoutEffectAlias])).with("setState", () => {
720
+ $(getCallKind(node)).with("setState", () => {
702
721
  if (!parentFn) return;
703
722
  if (parentFn !== effectFn && parentFnKind !== "immediate") {
704
723
  const maybeVd = ast.traverseUpGuard(node, isVariableDeclaratorFromHookCall);
@@ -713,7 +732,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
713
732
  return;
714
733
  }
715
734
  context.report({
716
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
735
+ messageId: "noDirectSetStateInUseLayoutEffect",
717
736
  node
718
737
  });
719
738
  }).with("useLayoutEffect", () => {
@@ -729,19 +748,20 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
729
748
  },
730
749
  Identifier(node) {
731
750
  if (!node.parent) return;
732
- if (!isFromUseStateCall(context, useStateAlias)(node)) return;
751
+ if (node.parent.type === ast.NodeType.CallExpression && node.parent.callee === node) return;
752
+ if (!isIdFromUseStateCall(node)) return;
733
753
  switch (node.parent.type) {
734
754
  case ast.NodeType.CallExpression: {
735
755
  const [firstArg] = node.parent.arguments;
736
756
  if (node !== firstArg) break;
737
- if (core.isReactHookCallWithNameAlias("useCallback", context, useStateAlias)(node.parent)) {
757
+ if (isUseCallbackCall2(node.parent)) {
738
758
  const maybeVd = ast.traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
739
759
  if (tools.O.isNone(maybeVd)) break;
740
760
  const vd = maybeVd.value;
741
761
  const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
742
762
  indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
743
763
  }
744
- if (core.isReactHookCallWithNameAlias("useLayoutEffect", context, useLayoutEffectAlias)(node.parent)) {
764
+ if (isUseEffectCall(node.parent)) {
745
765
  const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
746
766
  indirectSetStateCallsAsEFs.set(node.parent, [...calls, node]);
747
767
  }
@@ -750,7 +770,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
750
770
  case ast.NodeType.ArrowFunctionExpression: {
751
771
  const parent = node.parent.parent;
752
772
  if (parent?.type !== ast.NodeType.CallExpression) break;
753
- if (!core.isReactHookCallWithNameAlias("useMemo", context, useStateAlias)(parent)) break;
773
+ if (!isUseMemoCall2(parent)) break;
754
774
  const maybeVd = ast.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
755
775
  if (tools.O.isNone(maybeVd)) break;
756
776
  const vd = maybeVd.value;
@@ -776,7 +796,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
776
796
  for (const call of calls) {
777
797
  context.report({
778
798
  data: { name: call.name },
779
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
799
+ messageId: "noDirectSetStateInUseLayoutEffect",
780
800
  node: call
781
801
  });
782
802
  }
@@ -788,7 +808,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
788
808
  for (const setStateCall of setStateCalls) {
789
809
  context.report({
790
810
  data: { name: name2 },
791
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
811
+ messageId: "noDirectSetStateInUseLayoutEffect",
792
812
  node: setStateCall
793
813
  });
794
814
  }
@@ -798,7 +818,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
798
818
  for (const setStateCall of setStateCalls) {
799
819
  context.report({
800
820
  data: { name: id.name },
801
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
821
+ messageId: "noDirectSetStateInUseLayoutEffect",
802
822
  node: setStateCall
803
823
  });
804
824
  }
@@ -817,7 +837,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
817
837
  description: "disallow function calls in 'useState' that aren't wrapped in an initializer function"
818
838
  },
819
839
  messages: {
820
- PREFER_USE_STATE_LAZY_INITIALIZATION: "To prevent re-computation, consider using lazy initial state for useState calls that involve function calls. Ex: 'useState(() => getValue())'."
840
+ preferUseStateLazyInitialization: "To prevent re-computation, consider using lazy initial state for useState calls that involve function calls. Ex: 'useState(() => getValue())'."
821
841
  },
822
842
  schema: []
823
843
  },
@@ -836,7 +856,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
836
856
  });
837
857
  if (!hasFunctionCall) return;
838
858
  context.report({
839
- messageId: "PREFER_USE_STATE_LAZY_INITIALIZATION",
859
+ messageId: "preferUseStateLazyInitialization",
840
860
  node: useStateInput
841
861
  });
842
862
  }
package/dist/index.mjs CHANGED
@@ -8,21 +8,24 @@ import * as R from 'remeda';
8
8
 
9
9
  // package.json
10
10
  var name = "eslint-plugin-react-hooks-extra";
11
- var version = "1.8.2";
11
+ var version = "1.8.3-next.1";
12
12
  var createRule = createRuleForPlugin("hooks-extra");
13
- function isFromUseStateCall(context, useStateAlias) {
14
- return (topLevelId) => {
15
- const useStateCall = F.pipe(
16
- findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
17
- O.flatMap(getVariableNode(0)),
18
- O.filter(is(NodeType.CallExpression)),
19
- O.filter(isReactHookCallWithNameAlias("useState", context, useStateAlias))
20
- );
21
- if (O.isNone(useStateCall)) return false;
22
- const { parent } = useStateCall.value;
13
+ function isFromHookCall(name2, context, settings, predicate = F.constTrue) {
14
+ const hookAlias = settings.additionalHooks?.[name2] ?? [];
15
+ return (topLevelId) => F.pipe(
16
+ findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
17
+ O.flatMap(getVariableNode(0)),
18
+ O.filter(is(NodeType.CallExpression)),
19
+ O.filter(isReactHookCallWithNameAlias(name2, context, hookAlias)),
20
+ O.exists((call) => predicate(topLevelId, call))
21
+ );
22
+ }
23
+ function isFromUseStateCall(context, settings) {
24
+ return (toplevelId) => isFromHookCall("useState", context, settings, (topLevelId, call) => {
25
+ const { parent } = call;
23
26
  if (!("id" in parent && parent.id?.type === NodeType.ArrayPattern)) return true;
24
27
  return parent.id.elements.findIndex((e2) => e2?.type === NodeType.Identifier && e2.name === topLevelId.name) === 1;
25
- };
28
+ })(toplevelId);
26
29
  }
27
30
 
28
31
  // ../../../node_modules/.pnpm/ts-pattern@5.2.0/node_modules/ts-pattern/dist/index.js
@@ -208,18 +211,19 @@ var z = class _z {
208
211
  }
209
212
  };
210
213
 
211
- // src/utils/is-set-state-call.ts
212
- function isSetStateCall(context, useStateAlias) {
214
+ // src/utils/is-set-function-call.ts
215
+ function isSetFunctionCall(context, settings) {
216
+ const isIdFromUseStateCall = isFromUseStateCall(context, settings);
213
217
  return (node) => {
214
218
  switch (node.callee.type) {
215
219
  case NodeType.Identifier: {
216
- return isFromUseStateCall(context, useStateAlias)(node.callee);
220
+ return isIdFromUseStateCall(node.callee);
217
221
  }
218
222
  case NodeType.MemberExpression: {
219
223
  if (!("name" in node.callee.object)) return false;
220
224
  const initialScope = context.sourceCode.getScope(node);
221
225
  const property = getStaticValue(node.callee.property, initialScope);
222
- if (property?.value === 1) return isFromUseStateCall(context, useStateAlias)(node.callee.object);
226
+ if (property?.value === 1) return isIdFromUseStateCall(node.callee.object);
223
227
  return false;
224
228
  }
225
229
  case NodeType.CallExpression: {
@@ -237,7 +241,7 @@ function isSetStateCall(context, useStateAlias) {
237
241
  if (!isAt || !index) return false;
238
242
  const initialScope = context.sourceCode.getScope(node);
239
243
  const value = getStaticValue(index, initialScope);
240
- if (value?.value === 1) return isFromUseStateCall(context, useStateAlias)(callee.object);
244
+ if (value?.value === 1) return isIdFromUseStateCall(callee.object);
241
245
  return false;
242
246
  }
243
247
  default: {
@@ -272,7 +276,7 @@ var ensure_custom_hooks_using_other_hooks_default = createRule({
272
276
  description: "enforce custom hooks using other hooks"
273
277
  },
274
278
  messages: {
275
- ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS: "A custom hook '{{name}}' should use other hooks."
279
+ ensureCustomHooksUsingOtherHooks: "A custom hook '{{name}}' should use other hooks."
276
280
  },
277
281
  schema: []
278
282
  },
@@ -289,7 +293,7 @@ var ensure_custom_hooks_using_other_hooks_default = createRule({
289
293
  data: {
290
294
  name: name2.value
291
295
  },
292
- messageId: "ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS",
296
+ messageId: "ensureCustomHooksUsingOtherHooks",
293
297
  node: node2
294
298
  });
295
299
  }
@@ -306,7 +310,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
306
310
  description: "enforce 'useCallback' has non-empty dependencies array"
307
311
  },
308
312
  messages: {
309
- ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS: "An 'useCallback' should have a non-empty dependencies array."
313
+ ensureUseCallbackHasNonEmptyDeps: "An 'useCallback' should have a non-empty dependencies array."
310
314
  },
311
315
  schema: []
312
316
  },
@@ -326,7 +330,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
326
330
  const [cb, deps] = node.arguments;
327
331
  if (!deps) {
328
332
  context.report({
329
- messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
333
+ messageId: "ensureUseCallbackHasNonEmptyDeps",
330
334
  node
331
335
  });
332
336
  return;
@@ -344,7 +348,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
344
348
  if (!hasEmptyDeps) return;
345
349
  if (!cb) {
346
350
  context.report({
347
- messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
351
+ messageId: "ensureUseCallbackHasNonEmptyDeps",
348
352
  node
349
353
  });
350
354
  return;
@@ -368,7 +372,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
368
372
  );
369
373
  if (isReferencedToComponentScope) return;
370
374
  context.report({
371
- messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
375
+ messageId: "ensureUseCallbackHasNonEmptyDeps",
372
376
  node
373
377
  });
374
378
  }
@@ -384,7 +388,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
384
388
  description: "enforce 'useMemo' has non-empty dependencies array"
385
389
  },
386
390
  messages: {
387
- ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS: "An 'useMemo' should have a non-empty dependencies array."
391
+ ensureUseMemoHasNonEmptyDeps: "An 'useMemo' should have a non-empty dependencies array."
388
392
  },
389
393
  schema: []
390
394
  },
@@ -404,7 +408,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
404
408
  const [cb, deps] = node.arguments;
405
409
  if (!deps) {
406
410
  context.report({
407
- messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
411
+ messageId: "ensureUseMemoHasNonEmptyDeps",
408
412
  node
409
413
  });
410
414
  return;
@@ -422,7 +426,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
422
426
  if (!hasEmptyDeps) return;
423
427
  if (!cb) {
424
428
  context.report({
425
- messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
429
+ messageId: "ensureUseMemoHasNonEmptyDeps",
426
430
  node
427
431
  });
428
432
  return;
@@ -446,7 +450,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
446
450
  );
447
451
  if (isReferencedToComponentScope) return;
448
452
  context.report({
449
- messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
453
+ messageId: "ensureUseMemoHasNonEmptyDeps",
450
454
  node
451
455
  });
452
456
  }
@@ -455,16 +459,6 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
455
459
  defaultOptions: []
456
460
  });
457
461
  var RULE_NAME4 = "no-direct-set-state-in-use-effect";
458
- function isEffectFunction(context, useSomeEffectAlias) {
459
- return (node) => node.parent?.type === NodeType.CallExpression && node.parent.callee !== node && isReactHookCallWithNameAlias("useEffect", context, useSomeEffectAlias)(node.parent);
460
- }
461
- function getCallKind(node, context, alias) {
462
- const [useStateAlias, useEffectAlias] = alias;
463
- return $(node).when(isReactHookCallWithNameAlias("useState", context, useStateAlias), () => "useState").when(isReactHookCallWithNameAlias("useEffect", context, useEffectAlias), () => "useEffect").when(isSetStateCall(context, useStateAlias), () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
464
- }
465
- function getFunctionKind(node, context, useEffectAlias) {
466
- return $(node).when(isEffectFunction(context, useEffectAlias), () => "effect").when(isIIFE, () => "immediate").otherwise(() => "other");
467
- }
468
462
  var no_direct_set_state_in_use_effect_default = createRule({
469
463
  meta: {
470
464
  type: "problem",
@@ -472,14 +466,20 @@ var no_direct_set_state_in_use_effect_default = createRule({
472
466
  description: "disallow direct calls to the 'set' function of 'useState' in 'useEffect'"
473
467
  },
474
468
  messages: {
475
- NO_DIRECT_SET_STATE_IN_USE_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useEffect'."
469
+ noDirectSetStateInUseEffect: "Do not call the 'set' function of 'useState' directly in 'useEffect'."
476
470
  },
477
471
  schema: []
478
472
  },
479
473
  name: RULE_NAME4,
480
474
  create(context) {
481
475
  const settings = decodeSettings(context.settings);
482
- const { useEffect: useEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
476
+ const additionalHooks = settings.additionalHooks ?? {};
477
+ const isUseEffectCall = isReactHookCallWithNameAlias("useEffect", context, additionalHooks.useEffect ?? []);
478
+ const isUseStateCall2 = isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
479
+ const isUseMemoCall2 = isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
480
+ const isUseCallbackCall2 = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
481
+ const isSetStateCall = isSetFunctionCall(context, settings);
482
+ const isIdFromUseStateCall = isFromUseStateCall(context, settings);
483
483
  const functionStack = [];
484
484
  const effectFunctionRef = MutRef.make(null);
485
485
  const effectFunctionIdentifiers = [];
@@ -494,9 +494,18 @@ var no_direct_set_state_in_use_effect_default = createRule({
494
494
  const onEffectFunctionExit = (node) => {
495
495
  MutRef.update(effectFunctionRef, (current) => current === node ? null : current);
496
496
  };
497
+ function isEffectFunction(node) {
498
+ return node.parent?.type === NodeType.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
499
+ }
500
+ function getCallKind(node) {
501
+ return $(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
502
+ }
503
+ function getFunctionKind(node) {
504
+ return $(node).when(isEffectFunction, () => "effect").when(isIIFE, () => "immediate").otherwise(() => "other");
505
+ }
497
506
  return {
498
507
  ":function"(node) {
499
- const functionKind = getFunctionKind(node, context, useEffectAlias);
508
+ const functionKind = getFunctionKind(node);
500
509
  functionStack.push([node, functionKind]);
501
510
  $(functionKind).with("effect", () => {
502
511
  onEffectFunctionEnter(node);
@@ -510,7 +519,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
510
519
  const effectFn = MutRef.get(effectFunctionRef);
511
520
  const [parentFn, parentFnKind] = R.last(functionStack) ?? [];
512
521
  if (parentFn?.async) return;
513
- $(getCallKind(node, context, [useStateAlias, useEffectAlias])).with("setState", () => {
522
+ $(getCallKind(node)).with("setState", () => {
514
523
  if (!parentFn) return;
515
524
  if (parentFn !== effectFn && parentFnKind !== "immediate") {
516
525
  const maybeVd = traverseUpGuard(node, isVariableDeclaratorFromHookCall);
@@ -525,7 +534,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
525
534
  return;
526
535
  }
527
536
  context.report({
528
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
537
+ messageId: "noDirectSetStateInUseEffect",
529
538
  node
530
539
  });
531
540
  }).with("useEffect", () => {
@@ -541,19 +550,20 @@ var no_direct_set_state_in_use_effect_default = createRule({
541
550
  },
542
551
  Identifier(node) {
543
552
  if (!node.parent) return;
544
- if (!isFromUseStateCall(context, useStateAlias)(node)) return;
553
+ if (node.parent.type === NodeType.CallExpression && node.parent.callee === node) return;
554
+ if (!isIdFromUseStateCall(node)) return;
545
555
  switch (node.parent.type) {
546
556
  case NodeType.CallExpression: {
547
557
  const [firstArg] = node.parent.arguments;
548
558
  if (node !== firstArg) break;
549
- if (isReactHookCallWithNameAlias("useCallback", context, useStateAlias)(node.parent)) {
559
+ if (isUseCallbackCall2(node.parent)) {
550
560
  const maybeVd = traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
551
561
  if (O.isNone(maybeVd)) break;
552
562
  const vd = maybeVd.value;
553
563
  const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
554
564
  indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
555
565
  }
556
- if (isReactHookCallWithNameAlias("useEffect", context, useEffectAlias)(node.parent)) {
566
+ if (isUseEffectCall(node.parent)) {
557
567
  const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
558
568
  indirectSetStateCallsAsEFs.set(node.parent, [...calls, node]);
559
569
  }
@@ -562,7 +572,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
562
572
  case NodeType.ArrowFunctionExpression: {
563
573
  const parent = node.parent.parent;
564
574
  if (parent?.type !== NodeType.CallExpression) break;
565
- if (!isReactHookCallWithNameAlias("useMemo", context, useStateAlias)(parent)) break;
575
+ if (!isUseMemoCall2(parent)) break;
566
576
  const maybeVd = traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
567
577
  if (O.isNone(maybeVd)) break;
568
578
  const vd = maybeVd.value;
@@ -588,7 +598,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
588
598
  for (const call of calls) {
589
599
  context.report({
590
600
  data: { name: call.name },
591
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
601
+ messageId: "noDirectSetStateInUseEffect",
592
602
  node: call
593
603
  });
594
604
  }
@@ -600,7 +610,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
600
610
  for (const setStateCall of setStateCalls) {
601
611
  context.report({
602
612
  data: { name: name2 },
603
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
613
+ messageId: "noDirectSetStateInUseEffect",
604
614
  node: setStateCall
605
615
  });
606
616
  }
@@ -610,7 +620,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
610
620
  for (const setStateCall of setStateCalls) {
611
621
  context.report({
612
622
  data: { name: id.name },
613
- messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
623
+ messageId: "noDirectSetStateInUseEffect",
614
624
  node: setStateCall
615
625
  });
616
626
  }
@@ -621,16 +631,6 @@ var no_direct_set_state_in_use_effect_default = createRule({
621
631
  defaultOptions: []
622
632
  });
623
633
  var RULE_NAME5 = "no-direct-set-state-in-use-layout-effect";
624
- function isEffectFunction2(context, useSomeEffectAlias) {
625
- return (node) => node.parent?.type === NodeType.CallExpression && node.parent.callee !== node && isReactHookCallWithNameAlias("useLayoutEffect", context, useSomeEffectAlias)(node.parent);
626
- }
627
- function getCallKind2(node, context, alias) {
628
- const [useStateAlias, useLayoutEffectAlias] = alias;
629
- return $(node).when(isReactHookCallWithNameAlias("useState", context, useStateAlias), () => "useState").when(isReactHookCallWithNameAlias("useLayoutEffect", context, useLayoutEffectAlias), () => "useLayoutEffect").when(isSetStateCall(context, useStateAlias), () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
630
- }
631
- function getFunctionKind2(node, context, useLayoutEffectAlias) {
632
- return $(node).when(isEffectFunction2(context, useLayoutEffectAlias), () => "effect").when(isIIFE, () => "immediate").otherwise(() => "other");
633
- }
634
634
  var no_direct_set_state_in_use_layout_effect_default = createRule({
635
635
  meta: {
636
636
  type: "problem",
@@ -638,14 +638,24 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
638
638
  description: "disallow direct calls to the 'set' function of 'useState' in 'useLayoutEffect'"
639
639
  },
640
640
  messages: {
641
- NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useLayoutEffect'."
641
+ noDirectSetStateInUseLayoutEffect: "Do not call the 'set' function of 'useState' directly in 'useLayoutEffect'."
642
642
  },
643
643
  schema: []
644
644
  },
645
645
  name: RULE_NAME5,
646
646
  create(context) {
647
647
  const settings = decodeSettings(context.settings);
648
- const { useLayoutEffect: useLayoutEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
648
+ const additionalHooks = settings.additionalHooks ?? {};
649
+ const isUseEffectCall = isReactHookCallWithNameAlias(
650
+ "useLayoutEffect",
651
+ context,
652
+ additionalHooks.useLayoutEffect ?? []
653
+ );
654
+ const isUseStateCall2 = isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
655
+ const isUseMemoCall2 = isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
656
+ const isUseCallbackCall2 = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
657
+ const isSetStateCall = isSetFunctionCall(context, settings);
658
+ const isIdFromUseStateCall = isFromUseStateCall(context, settings);
649
659
  const functionStack = [];
650
660
  const effectFunctionRef = MutRef.make(null);
651
661
  const effectFunctionIdentifiers = [];
@@ -660,9 +670,18 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
660
670
  const onEffectFunctionExit = (node) => {
661
671
  MutRef.update(effectFunctionRef, (current) => current === node ? null : current);
662
672
  };
673
+ function isEffectFunction(node) {
674
+ return node.parent?.type === NodeType.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
675
+ }
676
+ function getCallKind(node) {
677
+ return $(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
678
+ }
679
+ function getFunctionKind(node) {
680
+ return $(node).when(isEffectFunction, () => "effect").when(isIIFE, () => "immediate").otherwise(() => "other");
681
+ }
663
682
  return {
664
683
  ":function"(node) {
665
- const functionKind = getFunctionKind2(node, context, useLayoutEffectAlias);
684
+ const functionKind = getFunctionKind(node);
666
685
  functionStack.push([node, functionKind]);
667
686
  $(functionKind).with("effect", () => {
668
687
  onEffectFunctionEnter(node);
@@ -676,7 +695,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
676
695
  const effectFn = MutRef.get(effectFunctionRef);
677
696
  const [parentFn, parentFnKind] = R.last(functionStack) ?? [];
678
697
  if (parentFn?.async) return;
679
- $(getCallKind2(node, context, [useStateAlias, useLayoutEffectAlias])).with("setState", () => {
698
+ $(getCallKind(node)).with("setState", () => {
680
699
  if (!parentFn) return;
681
700
  if (parentFn !== effectFn && parentFnKind !== "immediate") {
682
701
  const maybeVd = traverseUpGuard(node, isVariableDeclaratorFromHookCall);
@@ -691,7 +710,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
691
710
  return;
692
711
  }
693
712
  context.report({
694
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
713
+ messageId: "noDirectSetStateInUseLayoutEffect",
695
714
  node
696
715
  });
697
716
  }).with("useLayoutEffect", () => {
@@ -707,19 +726,20 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
707
726
  },
708
727
  Identifier(node) {
709
728
  if (!node.parent) return;
710
- if (!isFromUseStateCall(context, useStateAlias)(node)) return;
729
+ if (node.parent.type === NodeType.CallExpression && node.parent.callee === node) return;
730
+ if (!isIdFromUseStateCall(node)) return;
711
731
  switch (node.parent.type) {
712
732
  case NodeType.CallExpression: {
713
733
  const [firstArg] = node.parent.arguments;
714
734
  if (node !== firstArg) break;
715
- if (isReactHookCallWithNameAlias("useCallback", context, useStateAlias)(node.parent)) {
735
+ if (isUseCallbackCall2(node.parent)) {
716
736
  const maybeVd = traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
717
737
  if (O.isNone(maybeVd)) break;
718
738
  const vd = maybeVd.value;
719
739
  const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
720
740
  indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
721
741
  }
722
- if (isReactHookCallWithNameAlias("useLayoutEffect", context, useLayoutEffectAlias)(node.parent)) {
742
+ if (isUseEffectCall(node.parent)) {
723
743
  const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
724
744
  indirectSetStateCallsAsEFs.set(node.parent, [...calls, node]);
725
745
  }
@@ -728,7 +748,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
728
748
  case NodeType.ArrowFunctionExpression: {
729
749
  const parent = node.parent.parent;
730
750
  if (parent?.type !== NodeType.CallExpression) break;
731
- if (!isReactHookCallWithNameAlias("useMemo", context, useStateAlias)(parent)) break;
751
+ if (!isUseMemoCall2(parent)) break;
732
752
  const maybeVd = traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
733
753
  if (O.isNone(maybeVd)) break;
734
754
  const vd = maybeVd.value;
@@ -754,7 +774,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
754
774
  for (const call of calls) {
755
775
  context.report({
756
776
  data: { name: call.name },
757
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
777
+ messageId: "noDirectSetStateInUseLayoutEffect",
758
778
  node: call
759
779
  });
760
780
  }
@@ -766,7 +786,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
766
786
  for (const setStateCall of setStateCalls) {
767
787
  context.report({
768
788
  data: { name: name2 },
769
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
789
+ messageId: "noDirectSetStateInUseLayoutEffect",
770
790
  node: setStateCall
771
791
  });
772
792
  }
@@ -776,7 +796,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
776
796
  for (const setStateCall of setStateCalls) {
777
797
  context.report({
778
798
  data: { name: id.name },
779
- messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
799
+ messageId: "noDirectSetStateInUseLayoutEffect",
780
800
  node: setStateCall
781
801
  });
782
802
  }
@@ -795,7 +815,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
795
815
  description: "disallow function calls in 'useState' that aren't wrapped in an initializer function"
796
816
  },
797
817
  messages: {
798
- PREFER_USE_STATE_LAZY_INITIALIZATION: "To prevent re-computation, consider using lazy initial state for useState calls that involve function calls. Ex: 'useState(() => getValue())'."
818
+ preferUseStateLazyInitialization: "To prevent re-computation, consider using lazy initial state for useState calls that involve function calls. Ex: 'useState(() => getValue())'."
799
819
  },
800
820
  schema: []
801
821
  },
@@ -814,7 +834,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
814
834
  });
815
835
  if (!hasFunctionCall) return;
816
836
  context.report({
817
- messageId: "PREFER_USE_STATE_LAZY_INITIALIZATION",
837
+ messageId: "preferUseStateLazyInitialization",
818
838
  node: useStateInput
819
839
  });
820
840
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks-extra",
3
- "version": "1.8.2",
3
+ "version": "1.8.3-next.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.0.0",
47
47
  "@typescript-eslint/utils": "^8.0.0",
48
48
  "remeda": "^2.7.0",
49
- "@eslint-react/ast": "1.8.2",
50
- "@eslint-react/core": "1.8.2",
51
- "@eslint-react/jsx": "1.8.2",
52
- "@eslint-react/tools": "1.8.2",
53
- "@eslint-react/shared": "1.8.2",
54
- "@eslint-react/var": "1.8.2",
55
- "@eslint-react/types": "1.8.2"
49
+ "@eslint-react/ast": "1.8.3-next.1",
50
+ "@eslint-react/core": "1.8.3-next.1",
51
+ "@eslint-react/shared": "1.8.3-next.1",
52
+ "@eslint-react/jsx": "1.8.3-next.1",
53
+ "@eslint-react/tools": "1.8.3-next.1",
54
+ "@eslint-react/var": "1.8.3-next.1",
55
+ "@eslint-react/types": "1.8.3-next.1"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/react": "^18.3.3",