eslint-plugin-react-hooks-extra 1.5.28-beta.7 → 1.5.28-next.2
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/dist/index.js +89 -49
- package/dist/index.mjs +91 -51
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var astUtils = require('@typescript-eslint/utils/ast-utils');
|
|
|
9
9
|
|
|
10
10
|
// package.json
|
|
11
11
|
var name = "eslint-plugin-react-hooks-extra";
|
|
12
|
-
var version = "1.5.28-
|
|
12
|
+
var version = "1.5.28-next.2";
|
|
13
13
|
var createRule = shared.createRuleForPlugin("hooks-extra");
|
|
14
14
|
|
|
15
15
|
// src/rules/ensure-custom-hooks-using-other-hooks.ts
|
|
@@ -467,26 +467,29 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
467
467
|
return $(node).when(isEffectFunction, () => "effect").when(isCleanUpFunction, () => "cleanup").when(ast.isIIFE, () => "immediate").otherwise(() => "other");
|
|
468
468
|
}
|
|
469
469
|
const useEffectCallRef = tools.MutRef.make(null);
|
|
470
|
+
const callStack = tools.MutList.make();
|
|
470
471
|
const functionStack = tools.MutList.make();
|
|
471
472
|
const effectFunctionRef = tools.MutRef.make(null);
|
|
472
473
|
const cleanUpFunctionRef = tools.MutRef.make(null);
|
|
473
|
-
const indirectFunctionCalls =
|
|
474
|
+
const indirectFunctionCalls = [];
|
|
474
475
|
const indirectSetStateCalls = /* @__PURE__ */ new Map();
|
|
476
|
+
const onUseEffectCallEnter = (node) => void tools.MutRef.set(useEffectCallRef, node);
|
|
477
|
+
const onUseEffectCallExit = () => void tools.MutRef.set(useEffectCallRef, null);
|
|
475
478
|
return {
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
tools.MutList.
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
tools.MutList.pop(functionStack);
|
|
479
|
+
Identifier(node) {
|
|
480
|
+
const isInUseEffectCall = tools.MutRef.get(useEffectCallRef) !== null;
|
|
481
|
+
const parentFn = tools.MutList.tail(functionStack)?.[0];
|
|
482
|
+
const useEffectCall = tools.MutRef.get(useEffectCallRef);
|
|
483
|
+
const isEffectFunction2 = useEffectCall && tools.O.isSome(ast.traverseUp(useEffectCall, (n2) => n2 === parentFn));
|
|
484
|
+
if (isFromUseStateCall(node) && isInUseEffectCall && isEffectFunction2) {
|
|
485
|
+
context.report({
|
|
486
|
+
node,
|
|
487
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT"
|
|
488
|
+
});
|
|
489
|
+
}
|
|
488
490
|
},
|
|
489
491
|
CallExpression(node) {
|
|
492
|
+
tools.MutList.append(callStack, node);
|
|
490
493
|
const effectFn = tools.MutRef.get(effectFunctionRef);
|
|
491
494
|
const [parentFn, parentFnKind] = tools.MutList.tail(functionStack) ?? [];
|
|
492
495
|
if (parentFn?.async) return;
|
|
@@ -494,29 +497,47 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
494
497
|
$(callKind).with("setState", () => {
|
|
495
498
|
if (!parentFn) return;
|
|
496
499
|
if (parentFn !== effectFn && parentFnKind !== "immediate") {
|
|
497
|
-
|
|
498
|
-
indirectSetStateCalls.set(parentFn, tools.Chunk.append(calls, node));
|
|
500
|
+
indirectSetStateCalls.set(parentFn, [...indirectSetStateCalls.get(parentFn) ?? [], node]);
|
|
499
501
|
return;
|
|
500
502
|
}
|
|
501
503
|
context.report({
|
|
502
|
-
|
|
503
|
-
|
|
504
|
+
node,
|
|
505
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT"
|
|
504
506
|
});
|
|
505
507
|
}).with("useEffect", () => {
|
|
506
|
-
|
|
508
|
+
onUseEffectCallEnter(node);
|
|
509
|
+
}).with("useState", () => {
|
|
510
|
+
}).with("then", () => {
|
|
507
511
|
}).with("other", () => {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
+
indirectFunctionCalls.push(node);
|
|
513
|
+
}).exhaustive();
|
|
514
|
+
},
|
|
515
|
+
":function"(node) {
|
|
516
|
+
const functionKind = getFunctionKind(node);
|
|
517
|
+
tools.MutList.append(functionStack, [node, functionKind]);
|
|
518
|
+
$(functionKind).with("effect", () => {
|
|
519
|
+
tools.MutRef.set(effectFunctionRef, node);
|
|
520
|
+
}).with("cleanup", () => {
|
|
521
|
+
tools.MutRef.set(cleanUpFunctionRef, node);
|
|
522
|
+
}).otherwise(() => {
|
|
523
|
+
});
|
|
524
|
+
},
|
|
525
|
+
":function:exit"(node) {
|
|
526
|
+
const effectFn = tools.MutRef.get(effectFunctionRef);
|
|
527
|
+
if (effectFn === node) {
|
|
528
|
+
tools.MutRef.set(effectFunctionRef, null);
|
|
529
|
+
}
|
|
530
|
+
tools.MutList.pop(functionStack);
|
|
512
531
|
},
|
|
513
532
|
"CallExpression:exit"(node) {
|
|
533
|
+
tools.MutList.pop(callStack);
|
|
514
534
|
if (tools.MutRef.get(useEffectCallRef) === node) {
|
|
535
|
+
onUseEffectCallExit();
|
|
515
536
|
tools.MutRef.set(useEffectCallRef, null);
|
|
516
537
|
}
|
|
517
538
|
},
|
|
518
539
|
"Program:exit"() {
|
|
519
|
-
for (const call of
|
|
540
|
+
for (const call of indirectFunctionCalls) {
|
|
520
541
|
if (!("name" in call.callee)) continue;
|
|
521
542
|
const { name: name2 } = call.callee;
|
|
522
543
|
const setStateCalls = tools.F.pipe(
|
|
@@ -524,7 +545,6 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
524
545
|
tools.O.flatMap(_var.getVariableInit(0)),
|
|
525
546
|
tools.O.filter(ast.isFunction),
|
|
526
547
|
tools.O.flatMapNullable((init) => indirectSetStateCalls.get(init)),
|
|
527
|
-
tools.O.map(tools.Chunk.toReadonlyArray),
|
|
528
548
|
tools.O.getOrElse(() => [])
|
|
529
549
|
);
|
|
530
550
|
for (const setStateCall of setStateCalls) {
|
|
@@ -621,26 +641,29 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
621
641
|
return $(node).when(isEffectFunction, () => "effect").when(isCleanUpFunction, () => "cleanup").when(ast.isIIFE, () => "immediate").otherwise(() => "other");
|
|
622
642
|
}
|
|
623
643
|
const useLayoutEffectCallRef = tools.MutRef.make(null);
|
|
644
|
+
const callStack = tools.MutList.make();
|
|
624
645
|
const functionStack = tools.MutList.make();
|
|
625
646
|
const effectFunctionRef = tools.MutRef.make(null);
|
|
626
647
|
const cleanUpFunctionRef = tools.MutRef.make(null);
|
|
627
|
-
const indirectFunctionCalls =
|
|
648
|
+
const indirectFunctionCalls = [];
|
|
628
649
|
const indirectSetStateCalls = /* @__PURE__ */ new Map();
|
|
650
|
+
const onUseLayoutEffectCallEnter = (node) => void tools.MutRef.set(useLayoutEffectCallRef, node);
|
|
651
|
+
const onUseLayoutEffectCallExit = () => void tools.MutRef.set(useLayoutEffectCallRef, null);
|
|
629
652
|
return {
|
|
630
|
-
|
|
631
|
-
const
|
|
632
|
-
tools.MutList.
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
tools.MutList.pop(functionStack);
|
|
653
|
+
Identifier(node) {
|
|
654
|
+
const isInUseLayoutEffectCall = tools.MutRef.get(useLayoutEffectCallRef) !== null;
|
|
655
|
+
const parentFn = tools.MutList.tail(functionStack)?.[0];
|
|
656
|
+
const useLayoutEffectCall = tools.MutRef.get(useLayoutEffectCallRef);
|
|
657
|
+
const isEffectFunction2 = useLayoutEffectCall && tools.O.isSome(ast.traverseUp(useLayoutEffectCall, (n2) => n2 === parentFn));
|
|
658
|
+
if (isFromUseStateCall(node) && isInUseLayoutEffectCall && isEffectFunction2) {
|
|
659
|
+
context.report({
|
|
660
|
+
node,
|
|
661
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT"
|
|
662
|
+
});
|
|
663
|
+
}
|
|
642
664
|
},
|
|
643
665
|
CallExpression(node) {
|
|
666
|
+
tools.MutList.append(callStack, node);
|
|
644
667
|
const effectFn = tools.MutRef.get(effectFunctionRef);
|
|
645
668
|
const [parentFn, parentFnKind] = tools.MutList.tail(functionStack) ?? [];
|
|
646
669
|
if (parentFn?.async) return;
|
|
@@ -648,29 +671,47 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
648
671
|
$(callKind).with("setState", () => {
|
|
649
672
|
if (!parentFn) return;
|
|
650
673
|
if (parentFn !== effectFn && parentFnKind !== "immediate") {
|
|
651
|
-
|
|
652
|
-
indirectSetStateCalls.set(parentFn, tools.Chunk.append(calls, node));
|
|
674
|
+
indirectSetStateCalls.set(parentFn, [...indirectSetStateCalls.get(parentFn) ?? [], node]);
|
|
653
675
|
return;
|
|
654
676
|
}
|
|
655
677
|
context.report({
|
|
656
|
-
|
|
657
|
-
|
|
678
|
+
node,
|
|
679
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT"
|
|
658
680
|
});
|
|
659
681
|
}).with("useLayoutEffect", () => {
|
|
660
|
-
|
|
682
|
+
onUseLayoutEffectCallEnter(node);
|
|
683
|
+
}).with("useState", () => {
|
|
684
|
+
}).with("then", () => {
|
|
661
685
|
}).with("other", () => {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
686
|
+
indirectFunctionCalls.push(node);
|
|
687
|
+
}).exhaustive();
|
|
688
|
+
},
|
|
689
|
+
":function"(node) {
|
|
690
|
+
const functionKind = getFunctionKind(node);
|
|
691
|
+
tools.MutList.append(functionStack, [node, functionKind]);
|
|
692
|
+
$(functionKind).with("effect", () => {
|
|
693
|
+
tools.MutRef.set(effectFunctionRef, node);
|
|
694
|
+
}).with("cleanup", () => {
|
|
695
|
+
tools.MutRef.set(cleanUpFunctionRef, node);
|
|
696
|
+
}).otherwise(() => {
|
|
697
|
+
});
|
|
698
|
+
},
|
|
699
|
+
":function:exit"(node) {
|
|
700
|
+
const effectFn = tools.MutRef.get(effectFunctionRef);
|
|
701
|
+
if (effectFn === node) {
|
|
702
|
+
tools.MutRef.set(effectFunctionRef, null);
|
|
703
|
+
}
|
|
704
|
+
tools.MutList.pop(functionStack);
|
|
666
705
|
},
|
|
667
706
|
"CallExpression:exit"(node) {
|
|
707
|
+
tools.MutList.pop(callStack);
|
|
668
708
|
if (tools.MutRef.get(useLayoutEffectCallRef) === node) {
|
|
709
|
+
onUseLayoutEffectCallExit();
|
|
669
710
|
tools.MutRef.set(useLayoutEffectCallRef, null);
|
|
670
711
|
}
|
|
671
712
|
},
|
|
672
713
|
"Program:exit"() {
|
|
673
|
-
for (const call of
|
|
714
|
+
for (const call of indirectFunctionCalls) {
|
|
674
715
|
if (!("name" in call.callee)) continue;
|
|
675
716
|
const { name: name2 } = call.callee;
|
|
676
717
|
const setStateCalls = tools.F.pipe(
|
|
@@ -678,7 +719,6 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
678
719
|
tools.O.flatMap(_var.getVariableInit(0)),
|
|
679
720
|
tools.O.filter(ast.isFunction),
|
|
680
721
|
tools.O.flatMapNullable((init) => indirectSetStateCalls.get(init)),
|
|
681
|
-
tools.O.map(tools.Chunk.toReadonlyArray),
|
|
682
722
|
tools.O.getOrElse(() => [])
|
|
683
723
|
);
|
|
684
724
|
for (const setStateCall of setStateCalls) {
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { useHookCollector, isReactHookCall, isUseCallbackCall, isReactHookCallWithNameLoose, isUseMemoCall, isUseStateCall, isUseEffectCall, isUseLayoutEffectCall } from '@eslint-react/core';
|
|
2
2
|
import { createRuleForPlugin, getESLintReactSettings } from '@eslint-react/shared';
|
|
3
|
-
import { isFunction, NodeType, is, getNestedCallExpressions, isIIFE } from '@eslint-react/ast';
|
|
4
|
-
import { F, O, MutRef, MutList
|
|
3
|
+
import { isFunction, NodeType, is, traverseUp, getNestedCallExpressions, isIIFE } from '@eslint-react/ast';
|
|
4
|
+
import { F, O, MutRef, MutList } from '@eslint-react/tools';
|
|
5
5
|
import { findVariable, getVariableInit } from '@eslint-react/var';
|
|
6
6
|
import { getStaticValue } from '@typescript-eslint/utils/ast-utils';
|
|
7
7
|
|
|
8
8
|
// package.json
|
|
9
9
|
var name = "eslint-plugin-react-hooks-extra";
|
|
10
|
-
var version = "1.5.28-
|
|
10
|
+
var version = "1.5.28-next.2";
|
|
11
11
|
var createRule = createRuleForPlugin("hooks-extra");
|
|
12
12
|
|
|
13
13
|
// src/rules/ensure-custom-hooks-using-other-hooks.ts
|
|
@@ -465,26 +465,29 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
465
465
|
return $(node).when(isEffectFunction, () => "effect").when(isCleanUpFunction, () => "cleanup").when(isIIFE, () => "immediate").otherwise(() => "other");
|
|
466
466
|
}
|
|
467
467
|
const useEffectCallRef = MutRef.make(null);
|
|
468
|
+
const callStack = MutList.make();
|
|
468
469
|
const functionStack = MutList.make();
|
|
469
470
|
const effectFunctionRef = MutRef.make(null);
|
|
470
471
|
const cleanUpFunctionRef = MutRef.make(null);
|
|
471
|
-
const indirectFunctionCalls =
|
|
472
|
+
const indirectFunctionCalls = [];
|
|
472
473
|
const indirectSetStateCalls = /* @__PURE__ */ new Map();
|
|
474
|
+
const onUseEffectCallEnter = (node) => void MutRef.set(useEffectCallRef, node);
|
|
475
|
+
const onUseEffectCallExit = () => void MutRef.set(useEffectCallRef, null);
|
|
473
476
|
return {
|
|
474
|
-
|
|
475
|
-
const
|
|
476
|
-
MutList.
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
MutList.pop(functionStack);
|
|
477
|
+
Identifier(node) {
|
|
478
|
+
const isInUseEffectCall = MutRef.get(useEffectCallRef) !== null;
|
|
479
|
+
const parentFn = MutList.tail(functionStack)?.[0];
|
|
480
|
+
const useEffectCall = MutRef.get(useEffectCallRef);
|
|
481
|
+
const isEffectFunction2 = useEffectCall && O.isSome(traverseUp(useEffectCall, (n2) => n2 === parentFn));
|
|
482
|
+
if (isFromUseStateCall(node) && isInUseEffectCall && isEffectFunction2) {
|
|
483
|
+
context.report({
|
|
484
|
+
node,
|
|
485
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT"
|
|
486
|
+
});
|
|
487
|
+
}
|
|
486
488
|
},
|
|
487
489
|
CallExpression(node) {
|
|
490
|
+
MutList.append(callStack, node);
|
|
488
491
|
const effectFn = MutRef.get(effectFunctionRef);
|
|
489
492
|
const [parentFn, parentFnKind] = MutList.tail(functionStack) ?? [];
|
|
490
493
|
if (parentFn?.async) return;
|
|
@@ -492,29 +495,47 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
492
495
|
$(callKind).with("setState", () => {
|
|
493
496
|
if (!parentFn) return;
|
|
494
497
|
if (parentFn !== effectFn && parentFnKind !== "immediate") {
|
|
495
|
-
|
|
496
|
-
indirectSetStateCalls.set(parentFn, Chunk.append(calls, node));
|
|
498
|
+
indirectSetStateCalls.set(parentFn, [...indirectSetStateCalls.get(parentFn) ?? [], node]);
|
|
497
499
|
return;
|
|
498
500
|
}
|
|
499
501
|
context.report({
|
|
500
|
-
|
|
501
|
-
|
|
502
|
+
node,
|
|
503
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT"
|
|
502
504
|
});
|
|
503
505
|
}).with("useEffect", () => {
|
|
504
|
-
|
|
506
|
+
onUseEffectCallEnter(node);
|
|
507
|
+
}).with("useState", () => {
|
|
508
|
+
}).with("then", () => {
|
|
505
509
|
}).with("other", () => {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
+
indirectFunctionCalls.push(node);
|
|
511
|
+
}).exhaustive();
|
|
512
|
+
},
|
|
513
|
+
":function"(node) {
|
|
514
|
+
const functionKind = getFunctionKind(node);
|
|
515
|
+
MutList.append(functionStack, [node, functionKind]);
|
|
516
|
+
$(functionKind).with("effect", () => {
|
|
517
|
+
MutRef.set(effectFunctionRef, node);
|
|
518
|
+
}).with("cleanup", () => {
|
|
519
|
+
MutRef.set(cleanUpFunctionRef, node);
|
|
520
|
+
}).otherwise(() => {
|
|
521
|
+
});
|
|
522
|
+
},
|
|
523
|
+
":function:exit"(node) {
|
|
524
|
+
const effectFn = MutRef.get(effectFunctionRef);
|
|
525
|
+
if (effectFn === node) {
|
|
526
|
+
MutRef.set(effectFunctionRef, null);
|
|
527
|
+
}
|
|
528
|
+
MutList.pop(functionStack);
|
|
510
529
|
},
|
|
511
530
|
"CallExpression:exit"(node) {
|
|
531
|
+
MutList.pop(callStack);
|
|
512
532
|
if (MutRef.get(useEffectCallRef) === node) {
|
|
533
|
+
onUseEffectCallExit();
|
|
513
534
|
MutRef.set(useEffectCallRef, null);
|
|
514
535
|
}
|
|
515
536
|
},
|
|
516
537
|
"Program:exit"() {
|
|
517
|
-
for (const call of
|
|
538
|
+
for (const call of indirectFunctionCalls) {
|
|
518
539
|
if (!("name" in call.callee)) continue;
|
|
519
540
|
const { name: name2 } = call.callee;
|
|
520
541
|
const setStateCalls = F.pipe(
|
|
@@ -522,7 +543,6 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
522
543
|
O.flatMap(getVariableInit(0)),
|
|
523
544
|
O.filter(isFunction),
|
|
524
545
|
O.flatMapNullable((init) => indirectSetStateCalls.get(init)),
|
|
525
|
-
O.map(Chunk.toReadonlyArray),
|
|
526
546
|
O.getOrElse(() => [])
|
|
527
547
|
);
|
|
528
548
|
for (const setStateCall of setStateCalls) {
|
|
@@ -619,26 +639,29 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
619
639
|
return $(node).when(isEffectFunction, () => "effect").when(isCleanUpFunction, () => "cleanup").when(isIIFE, () => "immediate").otherwise(() => "other");
|
|
620
640
|
}
|
|
621
641
|
const useLayoutEffectCallRef = MutRef.make(null);
|
|
642
|
+
const callStack = MutList.make();
|
|
622
643
|
const functionStack = MutList.make();
|
|
623
644
|
const effectFunctionRef = MutRef.make(null);
|
|
624
645
|
const cleanUpFunctionRef = MutRef.make(null);
|
|
625
|
-
const indirectFunctionCalls =
|
|
646
|
+
const indirectFunctionCalls = [];
|
|
626
647
|
const indirectSetStateCalls = /* @__PURE__ */ new Map();
|
|
648
|
+
const onUseLayoutEffectCallEnter = (node) => void MutRef.set(useLayoutEffectCallRef, node);
|
|
649
|
+
const onUseLayoutEffectCallExit = () => void MutRef.set(useLayoutEffectCallRef, null);
|
|
627
650
|
return {
|
|
628
|
-
|
|
629
|
-
const
|
|
630
|
-
MutList.
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
MutList.pop(functionStack);
|
|
651
|
+
Identifier(node) {
|
|
652
|
+
const isInUseLayoutEffectCall = MutRef.get(useLayoutEffectCallRef) !== null;
|
|
653
|
+
const parentFn = MutList.tail(functionStack)?.[0];
|
|
654
|
+
const useLayoutEffectCall = MutRef.get(useLayoutEffectCallRef);
|
|
655
|
+
const isEffectFunction2 = useLayoutEffectCall && O.isSome(traverseUp(useLayoutEffectCall, (n2) => n2 === parentFn));
|
|
656
|
+
if (isFromUseStateCall(node) && isInUseLayoutEffectCall && isEffectFunction2) {
|
|
657
|
+
context.report({
|
|
658
|
+
node,
|
|
659
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT"
|
|
660
|
+
});
|
|
661
|
+
}
|
|
640
662
|
},
|
|
641
663
|
CallExpression(node) {
|
|
664
|
+
MutList.append(callStack, node);
|
|
642
665
|
const effectFn = MutRef.get(effectFunctionRef);
|
|
643
666
|
const [parentFn, parentFnKind] = MutList.tail(functionStack) ?? [];
|
|
644
667
|
if (parentFn?.async) return;
|
|
@@ -646,29 +669,47 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
646
669
|
$(callKind).with("setState", () => {
|
|
647
670
|
if (!parentFn) return;
|
|
648
671
|
if (parentFn !== effectFn && parentFnKind !== "immediate") {
|
|
649
|
-
|
|
650
|
-
indirectSetStateCalls.set(parentFn, Chunk.append(calls, node));
|
|
672
|
+
indirectSetStateCalls.set(parentFn, [...indirectSetStateCalls.get(parentFn) ?? [], node]);
|
|
651
673
|
return;
|
|
652
674
|
}
|
|
653
675
|
context.report({
|
|
654
|
-
|
|
655
|
-
|
|
676
|
+
node,
|
|
677
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT"
|
|
656
678
|
});
|
|
657
679
|
}).with("useLayoutEffect", () => {
|
|
658
|
-
|
|
680
|
+
onUseLayoutEffectCallEnter(node);
|
|
681
|
+
}).with("useState", () => {
|
|
682
|
+
}).with("then", () => {
|
|
659
683
|
}).with("other", () => {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
684
|
+
indirectFunctionCalls.push(node);
|
|
685
|
+
}).exhaustive();
|
|
686
|
+
},
|
|
687
|
+
":function"(node) {
|
|
688
|
+
const functionKind = getFunctionKind(node);
|
|
689
|
+
MutList.append(functionStack, [node, functionKind]);
|
|
690
|
+
$(functionKind).with("effect", () => {
|
|
691
|
+
MutRef.set(effectFunctionRef, node);
|
|
692
|
+
}).with("cleanup", () => {
|
|
693
|
+
MutRef.set(cleanUpFunctionRef, node);
|
|
694
|
+
}).otherwise(() => {
|
|
695
|
+
});
|
|
696
|
+
},
|
|
697
|
+
":function:exit"(node) {
|
|
698
|
+
const effectFn = MutRef.get(effectFunctionRef);
|
|
699
|
+
if (effectFn === node) {
|
|
700
|
+
MutRef.set(effectFunctionRef, null);
|
|
701
|
+
}
|
|
702
|
+
MutList.pop(functionStack);
|
|
664
703
|
},
|
|
665
704
|
"CallExpression:exit"(node) {
|
|
705
|
+
MutList.pop(callStack);
|
|
666
706
|
if (MutRef.get(useLayoutEffectCallRef) === node) {
|
|
707
|
+
onUseLayoutEffectCallExit();
|
|
667
708
|
MutRef.set(useLayoutEffectCallRef, null);
|
|
668
709
|
}
|
|
669
710
|
},
|
|
670
711
|
"Program:exit"() {
|
|
671
|
-
for (const call of
|
|
712
|
+
for (const call of indirectFunctionCalls) {
|
|
672
713
|
if (!("name" in call.callee)) continue;
|
|
673
714
|
const { name: name2 } = call.callee;
|
|
674
715
|
const setStateCalls = F.pipe(
|
|
@@ -676,7 +717,6 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
676
717
|
O.flatMap(getVariableInit(0)),
|
|
677
718
|
O.filter(isFunction),
|
|
678
719
|
O.flatMapNullable((init) => indirectSetStateCalls.get(init)),
|
|
679
|
-
O.map(Chunk.toReadonlyArray),
|
|
680
720
|
O.getOrElse(() => [])
|
|
681
721
|
);
|
|
682
722
|
for (const setStateCall of setStateCalls) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-hooks-extra",
|
|
3
|
-
"version": "1.5.28-
|
|
3
|
+
"version": "1.5.28-next.2",
|
|
4
4
|
"description": "ESLint React's ESLint plugin for React Hooks related rules.",
|
|
5
5
|
"homepage": "https://github.com/rel1cx/eslint-react",
|
|
6
6
|
"bugs": {
|
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
"@typescript-eslint/type-utils": "^7.16.1",
|
|
40
40
|
"@typescript-eslint/types": "^7.16.1",
|
|
41
41
|
"@typescript-eslint/utils": "^7.16.1",
|
|
42
|
-
"@eslint-react/ast": "1.5.28-
|
|
43
|
-
"@eslint-react/core": "1.5.28-
|
|
44
|
-
"@eslint-react/
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/
|
|
42
|
+
"@eslint-react/ast": "1.5.28-next.2",
|
|
43
|
+
"@eslint-react/core": "1.5.28-next.2",
|
|
44
|
+
"@eslint-react/shared": "1.5.28-next.2",
|
|
45
|
+
"@eslint-react/types": "1.5.28-next.2",
|
|
46
|
+
"@eslint-react/var": "1.5.28-next.2",
|
|
47
|
+
"@eslint-react/jsx": "1.5.28-next.2",
|
|
48
|
+
"@eslint-react/tools": "1.5.28-next.2"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"string-ts": "2.2.0",
|