eslint-plugin-react-hooks-extra 1.10.1-next.4 → 1.10.2-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 +8 -8
- package/dist/index.js +43 -31
- package/dist/index.mjs +43 -31
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -26,15 +26,15 @@ export default [
|
|
|
26
26
|
js.configs.recommended,
|
|
27
27
|
{
|
|
28
28
|
files: ["**/*.{ts,tsx}"],
|
|
29
|
-
plugins:
|
|
29
|
+
plugins: {
|
|
30
30
|
"react-hooks-extra": reactHooksExtra,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
},
|
|
32
|
+
rules: {
|
|
33
|
+
// react-hooks-extra recommended rules
|
|
34
|
+
"react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
|
|
35
|
+
"react-hooks-extra/no-direct-set-state-in-use-layout-effect": "warn",
|
|
36
|
+
"react-hooks-extra/prefer-use-state-lazy-initialization": "warn",
|
|
37
|
+
},
|
|
38
38
|
},
|
|
39
39
|
];
|
|
40
40
|
```
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ var tsPattern = require('ts-pattern');
|
|
|
11
11
|
|
|
12
12
|
// package.json
|
|
13
13
|
var name = "eslint-plugin-react-hooks-extra";
|
|
14
|
-
var version = "1.10.
|
|
14
|
+
var version = "1.10.2-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] ?? [];
|
|
@@ -35,9 +35,13 @@ function isSetFunctionCall(context, settings) {
|
|
|
35
35
|
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
36
36
|
return (node) => {
|
|
37
37
|
switch (node.callee.type) {
|
|
38
|
+
// const [data, setData] = useState();
|
|
39
|
+
// setData();
|
|
38
40
|
case types.AST_NODE_TYPES.Identifier: {
|
|
39
41
|
return isIdFromUseStateCall(node.callee);
|
|
40
42
|
}
|
|
43
|
+
// const data = useState();
|
|
44
|
+
// data[1]();
|
|
41
45
|
case types.AST_NODE_TYPES.MemberExpression: {
|
|
42
46
|
if (!("name" in node.callee.object)) return false;
|
|
43
47
|
const initialScope = context.sourceCode.getScope(node);
|
|
@@ -45,6 +49,8 @@ function isSetFunctionCall(context, settings) {
|
|
|
45
49
|
if (property?.value === 1) return isIdFromUseStateCall(node.callee.object);
|
|
46
50
|
return false;
|
|
47
51
|
}
|
|
52
|
+
// const data = useState();
|
|
53
|
+
// data.at(1)();
|
|
48
54
|
case types.AST_NODE_TYPES.CallExpression: {
|
|
49
55
|
const callee = node.callee.callee;
|
|
50
56
|
if (callee.type !== types.AST_NODE_TYPES.MemberExpression) return false;
|
|
@@ -101,6 +107,7 @@ var ensure_custom_hooks_using_other_hooks_default = createRule({
|
|
|
101
107
|
},
|
|
102
108
|
name: RULE_NAME,
|
|
103
109
|
create(context) {
|
|
110
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
104
111
|
const { ctx, listeners } = core.useHookCollector();
|
|
105
112
|
return {
|
|
106
113
|
...listeners,
|
|
@@ -135,6 +142,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
135
142
|
},
|
|
136
143
|
name: RULE_NAME2,
|
|
137
144
|
create(context) {
|
|
145
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
138
146
|
const alias = shared.decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
|
|
139
147
|
return {
|
|
140
148
|
CallExpression(node) {
|
|
@@ -213,6 +221,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
213
221
|
},
|
|
214
222
|
name: RULE_NAME3,
|
|
215
223
|
create(context) {
|
|
224
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
216
225
|
const alias = shared.decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
|
|
217
226
|
return {
|
|
218
227
|
CallExpression(node) {
|
|
@@ -291,6 +300,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
291
300
|
},
|
|
292
301
|
name: RULE_NAME4,
|
|
293
302
|
create(context) {
|
|
303
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
294
304
|
const settings = shared.decodeSettings(context.settings);
|
|
295
305
|
const additionalHooks = settings.additionalHooks ?? {};
|
|
296
306
|
const isUseEffectCall = core.isReactHookCallWithNameAlias("useEffect", context, additionalHooks.useEffect ?? []);
|
|
@@ -300,41 +310,41 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
300
310
|
const isSetStateCall = isSetFunctionCall(context, settings);
|
|
301
311
|
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
302
312
|
const functionStack = [];
|
|
303
|
-
const
|
|
304
|
-
const
|
|
313
|
+
const setupFunctionRef = tools.MutRef.make(null);
|
|
314
|
+
const setupFunctionIdentifiers = [];
|
|
305
315
|
const indirectFunctionCalls = [];
|
|
306
316
|
const indirectSetStateCalls = /* @__PURE__ */ new WeakMap();
|
|
307
317
|
const indirectSetStateCallsAsEFs = /* @__PURE__ */ new Map();
|
|
308
318
|
const indirectSetStateCallsAsArgs = /* @__PURE__ */ new WeakMap();
|
|
309
319
|
const indirectSetStateCallsInHooks = /* @__PURE__ */ new WeakMap();
|
|
310
|
-
const
|
|
311
|
-
tools.MutRef.set(
|
|
320
|
+
const onSetupFunctionEnter = (node) => {
|
|
321
|
+
tools.MutRef.set(setupFunctionRef, node);
|
|
312
322
|
};
|
|
313
|
-
const
|
|
314
|
-
tools.MutRef.update(
|
|
323
|
+
const onSetupFunctionExit = (node) => {
|
|
324
|
+
tools.MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
|
|
315
325
|
};
|
|
316
|
-
function
|
|
326
|
+
function isSetupFunction(node) {
|
|
317
327
|
return node.parent?.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
|
|
318
328
|
}
|
|
319
329
|
function getCallKind(node) {
|
|
320
330
|
return tsPattern.match(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
321
331
|
}
|
|
322
332
|
function getFunctionKind(node) {
|
|
323
|
-
return tsPattern.match(node).when(
|
|
333
|
+
return tsPattern.match(node).when(isSetupFunction, () => "setup").when(ast.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
|
|
324
334
|
}
|
|
325
335
|
return {
|
|
326
336
|
":function"(node) {
|
|
327
337
|
const functionKind = getFunctionKind(node);
|
|
328
338
|
functionStack.push([node, functionKind]);
|
|
329
|
-
if (functionKind === "
|
|
339
|
+
if (functionKind === "setup") onSetupFunctionEnter(node);
|
|
330
340
|
},
|
|
331
341
|
":function:exit"(node) {
|
|
332
342
|
const [_, functionKind] = functionStack.at(-1) ?? [];
|
|
333
343
|
functionStack.pop();
|
|
334
|
-
if (functionKind === "
|
|
344
|
+
if (functionKind === "setup") onSetupFunctionExit(node);
|
|
335
345
|
},
|
|
336
346
|
CallExpression(node) {
|
|
337
|
-
const effectFn = tools.MutRef.get(
|
|
347
|
+
const effectFn = tools.MutRef.get(setupFunctionRef);
|
|
338
348
|
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
|
|
339
349
|
if (parentFn?.async) return;
|
|
340
350
|
tsPattern.match(getCallKind(node)).with("setState", () => {
|
|
@@ -359,10 +369,10 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
359
369
|
const [firstArg] = node.arguments;
|
|
360
370
|
if (ast.isFunction(firstArg)) return;
|
|
361
371
|
const identifiers = ast.getNestedIdentifiers(node);
|
|
362
|
-
|
|
372
|
+
setupFunctionIdentifiers.push(...identifiers);
|
|
363
373
|
}).with("other", () => {
|
|
364
|
-
const
|
|
365
|
-
if (!
|
|
374
|
+
const isInSetupFunction = effectFn === parentFn;
|
|
375
|
+
if (!isInSetupFunction) return;
|
|
366
376
|
indirectFunctionCalls.push(node);
|
|
367
377
|
}).otherwise(tools.F.constVoid);
|
|
368
378
|
},
|
|
@@ -432,7 +442,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
432
442
|
});
|
|
433
443
|
}
|
|
434
444
|
}
|
|
435
|
-
for (const id of
|
|
445
|
+
for (const id of setupFunctionIdentifiers) {
|
|
436
446
|
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
437
447
|
for (const setStateCall of setStateCalls) {
|
|
438
448
|
context.report({
|
|
@@ -461,6 +471,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
461
471
|
},
|
|
462
472
|
name: RULE_NAME5,
|
|
463
473
|
create(context) {
|
|
474
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
464
475
|
const settings = shared.decodeSettings(context.settings);
|
|
465
476
|
const additionalHooks = settings.additionalHooks ?? {};
|
|
466
477
|
const isUseEffectCall = core.isReactHookCallWithNameAlias(
|
|
@@ -474,41 +485,41 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
474
485
|
const isSetStateCall = isSetFunctionCall(context, settings);
|
|
475
486
|
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
476
487
|
const functionStack = [];
|
|
477
|
-
const
|
|
478
|
-
const
|
|
488
|
+
const setupFunctionRef = tools.MutRef.make(null);
|
|
489
|
+
const setupFunctionIdentifiers = [];
|
|
479
490
|
const indirectFunctionCalls = [];
|
|
480
491
|
const indirectSetStateCalls = /* @__PURE__ */ new WeakMap();
|
|
481
492
|
const indirectSetStateCallsAsEFs = /* @__PURE__ */ new Map();
|
|
482
493
|
const indirectSetStateCallsAsArgs = /* @__PURE__ */ new WeakMap();
|
|
483
494
|
const indirectSetStateCallsInHooks = /* @__PURE__ */ new WeakMap();
|
|
484
|
-
const
|
|
485
|
-
tools.MutRef.set(
|
|
495
|
+
const onSetupFunctionEnter = (node) => {
|
|
496
|
+
tools.MutRef.set(setupFunctionRef, node);
|
|
486
497
|
};
|
|
487
|
-
const
|
|
488
|
-
tools.MutRef.update(
|
|
498
|
+
const onSetupFunctionExit = (node) => {
|
|
499
|
+
tools.MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
|
|
489
500
|
};
|
|
490
|
-
function
|
|
501
|
+
function isSetupFunction(node) {
|
|
491
502
|
return node.parent?.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
|
|
492
503
|
}
|
|
493
504
|
function getCallKind(node) {
|
|
494
505
|
return tsPattern.match(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
495
506
|
}
|
|
496
507
|
function getFunctionKind(node) {
|
|
497
|
-
return tsPattern.match(node).when(
|
|
508
|
+
return tsPattern.match(node).when(isSetupFunction, () => "setup").when(ast.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
|
|
498
509
|
}
|
|
499
510
|
return {
|
|
500
511
|
":function"(node) {
|
|
501
512
|
const functionKind = getFunctionKind(node);
|
|
502
513
|
functionStack.push([node, functionKind]);
|
|
503
|
-
if (functionKind === "
|
|
514
|
+
if (functionKind === "setup") onSetupFunctionEnter(node);
|
|
504
515
|
},
|
|
505
516
|
":function:exit"(node) {
|
|
506
517
|
const [_, functionKind] = functionStack.at(-1) ?? [];
|
|
507
518
|
functionStack.pop();
|
|
508
|
-
if (functionKind === "
|
|
519
|
+
if (functionKind === "setup") onSetupFunctionExit(node);
|
|
509
520
|
},
|
|
510
521
|
CallExpression(node) {
|
|
511
|
-
const effectFn = tools.MutRef.get(
|
|
522
|
+
const effectFn = tools.MutRef.get(setupFunctionRef);
|
|
512
523
|
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
|
|
513
524
|
if (parentFn?.async) return;
|
|
514
525
|
tsPattern.match(getCallKind(node)).with("setState", () => {
|
|
@@ -533,10 +544,10 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
533
544
|
const [firstArg] = node.arguments;
|
|
534
545
|
if (ast.isFunction(firstArg)) return;
|
|
535
546
|
const identifiers = ast.getNestedIdentifiers(node);
|
|
536
|
-
|
|
547
|
+
setupFunctionIdentifiers.push(...identifiers);
|
|
537
548
|
}).with("other", () => {
|
|
538
|
-
const
|
|
539
|
-
if (!
|
|
549
|
+
const isInSetupFunction = effectFn === parentFn;
|
|
550
|
+
if (!isInSetupFunction) return;
|
|
540
551
|
indirectFunctionCalls.push(node);
|
|
541
552
|
}).otherwise(tools.F.constVoid);
|
|
542
553
|
},
|
|
@@ -606,7 +617,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
606
617
|
});
|
|
607
618
|
}
|
|
608
619
|
}
|
|
609
|
-
for (const id of
|
|
620
|
+
for (const id of setupFunctionIdentifiers) {
|
|
610
621
|
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
611
622
|
for (const setStateCall of setStateCalls) {
|
|
612
623
|
context.report({
|
|
@@ -636,6 +647,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
|
|
|
636
647
|
},
|
|
637
648
|
name: RULE_NAME6,
|
|
638
649
|
create(context) {
|
|
650
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
639
651
|
const alias = shared.decodeSettings(context.settings).additionalHooks?.useState ?? [];
|
|
640
652
|
return {
|
|
641
653
|
CallExpression(node) {
|
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { match, isMatching } from 'ts-pattern';
|
|
|
9
9
|
|
|
10
10
|
// package.json
|
|
11
11
|
var name = "eslint-plugin-react-hooks-extra";
|
|
12
|
-
var version = "1.10.
|
|
12
|
+
var version = "1.10.2-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] ?? [];
|
|
@@ -33,9 +33,13 @@ function isSetFunctionCall(context, settings) {
|
|
|
33
33
|
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
34
34
|
return (node) => {
|
|
35
35
|
switch (node.callee.type) {
|
|
36
|
+
// const [data, setData] = useState();
|
|
37
|
+
// setData();
|
|
36
38
|
case AST_NODE_TYPES.Identifier: {
|
|
37
39
|
return isIdFromUseStateCall(node.callee);
|
|
38
40
|
}
|
|
41
|
+
// const data = useState();
|
|
42
|
+
// data[1]();
|
|
39
43
|
case AST_NODE_TYPES.MemberExpression: {
|
|
40
44
|
if (!("name" in node.callee.object)) return false;
|
|
41
45
|
const initialScope = context.sourceCode.getScope(node);
|
|
@@ -43,6 +47,8 @@ function isSetFunctionCall(context, settings) {
|
|
|
43
47
|
if (property?.value === 1) return isIdFromUseStateCall(node.callee.object);
|
|
44
48
|
return false;
|
|
45
49
|
}
|
|
50
|
+
// const data = useState();
|
|
51
|
+
// data.at(1)();
|
|
46
52
|
case AST_NODE_TYPES.CallExpression: {
|
|
47
53
|
const callee = node.callee.callee;
|
|
48
54
|
if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;
|
|
@@ -99,6 +105,7 @@ var ensure_custom_hooks_using_other_hooks_default = createRule({
|
|
|
99
105
|
},
|
|
100
106
|
name: RULE_NAME,
|
|
101
107
|
create(context) {
|
|
108
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
102
109
|
const { ctx, listeners } = useHookCollector();
|
|
103
110
|
return {
|
|
104
111
|
...listeners,
|
|
@@ -133,6 +140,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
133
140
|
},
|
|
134
141
|
name: RULE_NAME2,
|
|
135
142
|
create(context) {
|
|
143
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
136
144
|
const alias = decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
|
|
137
145
|
return {
|
|
138
146
|
CallExpression(node) {
|
|
@@ -211,6 +219,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
211
219
|
},
|
|
212
220
|
name: RULE_NAME3,
|
|
213
221
|
create(context) {
|
|
222
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
214
223
|
const alias = decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
|
|
215
224
|
return {
|
|
216
225
|
CallExpression(node) {
|
|
@@ -289,6 +298,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
289
298
|
},
|
|
290
299
|
name: RULE_NAME4,
|
|
291
300
|
create(context) {
|
|
301
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
292
302
|
const settings = decodeSettings(context.settings);
|
|
293
303
|
const additionalHooks = settings.additionalHooks ?? {};
|
|
294
304
|
const isUseEffectCall = isReactHookCallWithNameAlias("useEffect", context, additionalHooks.useEffect ?? []);
|
|
@@ -298,41 +308,41 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
298
308
|
const isSetStateCall = isSetFunctionCall(context, settings);
|
|
299
309
|
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
300
310
|
const functionStack = [];
|
|
301
|
-
const
|
|
302
|
-
const
|
|
311
|
+
const setupFunctionRef = MutRef.make(null);
|
|
312
|
+
const setupFunctionIdentifiers = [];
|
|
303
313
|
const indirectFunctionCalls = [];
|
|
304
314
|
const indirectSetStateCalls = /* @__PURE__ */ new WeakMap();
|
|
305
315
|
const indirectSetStateCallsAsEFs = /* @__PURE__ */ new Map();
|
|
306
316
|
const indirectSetStateCallsAsArgs = /* @__PURE__ */ new WeakMap();
|
|
307
317
|
const indirectSetStateCallsInHooks = /* @__PURE__ */ new WeakMap();
|
|
308
|
-
const
|
|
309
|
-
MutRef.set(
|
|
318
|
+
const onSetupFunctionEnter = (node) => {
|
|
319
|
+
MutRef.set(setupFunctionRef, node);
|
|
310
320
|
};
|
|
311
|
-
const
|
|
312
|
-
MutRef.update(
|
|
321
|
+
const onSetupFunctionExit = (node) => {
|
|
322
|
+
MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
|
|
313
323
|
};
|
|
314
|
-
function
|
|
324
|
+
function isSetupFunction(node) {
|
|
315
325
|
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
|
|
316
326
|
}
|
|
317
327
|
function getCallKind(node) {
|
|
318
328
|
return match(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
319
329
|
}
|
|
320
330
|
function getFunctionKind(node) {
|
|
321
|
-
return match(node).when(
|
|
331
|
+
return match(node).when(isSetupFunction, () => "setup").when(isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
|
|
322
332
|
}
|
|
323
333
|
return {
|
|
324
334
|
":function"(node) {
|
|
325
335
|
const functionKind = getFunctionKind(node);
|
|
326
336
|
functionStack.push([node, functionKind]);
|
|
327
|
-
if (functionKind === "
|
|
337
|
+
if (functionKind === "setup") onSetupFunctionEnter(node);
|
|
328
338
|
},
|
|
329
339
|
":function:exit"(node) {
|
|
330
340
|
const [_, functionKind] = functionStack.at(-1) ?? [];
|
|
331
341
|
functionStack.pop();
|
|
332
|
-
if (functionKind === "
|
|
342
|
+
if (functionKind === "setup") onSetupFunctionExit(node);
|
|
333
343
|
},
|
|
334
344
|
CallExpression(node) {
|
|
335
|
-
const effectFn = MutRef.get(
|
|
345
|
+
const effectFn = MutRef.get(setupFunctionRef);
|
|
336
346
|
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
|
|
337
347
|
if (parentFn?.async) return;
|
|
338
348
|
match(getCallKind(node)).with("setState", () => {
|
|
@@ -357,10 +367,10 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
357
367
|
const [firstArg] = node.arguments;
|
|
358
368
|
if (isFunction(firstArg)) return;
|
|
359
369
|
const identifiers = getNestedIdentifiers(node);
|
|
360
|
-
|
|
370
|
+
setupFunctionIdentifiers.push(...identifiers);
|
|
361
371
|
}).with("other", () => {
|
|
362
|
-
const
|
|
363
|
-
if (!
|
|
372
|
+
const isInSetupFunction = effectFn === parentFn;
|
|
373
|
+
if (!isInSetupFunction) return;
|
|
364
374
|
indirectFunctionCalls.push(node);
|
|
365
375
|
}).otherwise(F.constVoid);
|
|
366
376
|
},
|
|
@@ -430,7 +440,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
430
440
|
});
|
|
431
441
|
}
|
|
432
442
|
}
|
|
433
|
-
for (const id of
|
|
443
|
+
for (const id of setupFunctionIdentifiers) {
|
|
434
444
|
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
435
445
|
for (const setStateCall of setStateCalls) {
|
|
436
446
|
context.report({
|
|
@@ -459,6 +469,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
459
469
|
},
|
|
460
470
|
name: RULE_NAME5,
|
|
461
471
|
create(context) {
|
|
472
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
462
473
|
const settings = decodeSettings(context.settings);
|
|
463
474
|
const additionalHooks = settings.additionalHooks ?? {};
|
|
464
475
|
const isUseEffectCall = isReactHookCallWithNameAlias(
|
|
@@ -472,41 +483,41 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
472
483
|
const isSetStateCall = isSetFunctionCall(context, settings);
|
|
473
484
|
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
474
485
|
const functionStack = [];
|
|
475
|
-
const
|
|
476
|
-
const
|
|
486
|
+
const setupFunctionRef = MutRef.make(null);
|
|
487
|
+
const setupFunctionIdentifiers = [];
|
|
477
488
|
const indirectFunctionCalls = [];
|
|
478
489
|
const indirectSetStateCalls = /* @__PURE__ */ new WeakMap();
|
|
479
490
|
const indirectSetStateCallsAsEFs = /* @__PURE__ */ new Map();
|
|
480
491
|
const indirectSetStateCallsAsArgs = /* @__PURE__ */ new WeakMap();
|
|
481
492
|
const indirectSetStateCallsInHooks = /* @__PURE__ */ new WeakMap();
|
|
482
|
-
const
|
|
483
|
-
MutRef.set(
|
|
493
|
+
const onSetupFunctionEnter = (node) => {
|
|
494
|
+
MutRef.set(setupFunctionRef, node);
|
|
484
495
|
};
|
|
485
|
-
const
|
|
486
|
-
MutRef.update(
|
|
496
|
+
const onSetupFunctionExit = (node) => {
|
|
497
|
+
MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
|
|
487
498
|
};
|
|
488
|
-
function
|
|
499
|
+
function isSetupFunction(node) {
|
|
489
500
|
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectCall(node.parent);
|
|
490
501
|
}
|
|
491
502
|
function getCallKind(node) {
|
|
492
503
|
return match(node).when(isUseStateCall2, () => "useState").when(isUseEffectCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
493
504
|
}
|
|
494
505
|
function getFunctionKind(node) {
|
|
495
|
-
return match(node).when(
|
|
506
|
+
return match(node).when(isSetupFunction, () => "setup").when(isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
|
|
496
507
|
}
|
|
497
508
|
return {
|
|
498
509
|
":function"(node) {
|
|
499
510
|
const functionKind = getFunctionKind(node);
|
|
500
511
|
functionStack.push([node, functionKind]);
|
|
501
|
-
if (functionKind === "
|
|
512
|
+
if (functionKind === "setup") onSetupFunctionEnter(node);
|
|
502
513
|
},
|
|
503
514
|
":function:exit"(node) {
|
|
504
515
|
const [_, functionKind] = functionStack.at(-1) ?? [];
|
|
505
516
|
functionStack.pop();
|
|
506
|
-
if (functionKind === "
|
|
517
|
+
if (functionKind === "setup") onSetupFunctionExit(node);
|
|
507
518
|
},
|
|
508
519
|
CallExpression(node) {
|
|
509
|
-
const effectFn = MutRef.get(
|
|
520
|
+
const effectFn = MutRef.get(setupFunctionRef);
|
|
510
521
|
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
|
|
511
522
|
if (parentFn?.async) return;
|
|
512
523
|
match(getCallKind(node)).with("setState", () => {
|
|
@@ -531,10 +542,10 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
531
542
|
const [firstArg] = node.arguments;
|
|
532
543
|
if (isFunction(firstArg)) return;
|
|
533
544
|
const identifiers = getNestedIdentifiers(node);
|
|
534
|
-
|
|
545
|
+
setupFunctionIdentifiers.push(...identifiers);
|
|
535
546
|
}).with("other", () => {
|
|
536
|
-
const
|
|
537
|
-
if (!
|
|
547
|
+
const isInSetupFunction = effectFn === parentFn;
|
|
548
|
+
if (!isInSetupFunction) return;
|
|
538
549
|
indirectFunctionCalls.push(node);
|
|
539
550
|
}).otherwise(F.constVoid);
|
|
540
551
|
},
|
|
@@ -604,7 +615,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
|
604
615
|
});
|
|
605
616
|
}
|
|
606
617
|
}
|
|
607
|
-
for (const id of
|
|
618
|
+
for (const id of setupFunctionIdentifiers) {
|
|
608
619
|
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
609
620
|
for (const setStateCall of setStateCalls) {
|
|
610
621
|
context.report({
|
|
@@ -634,6 +645,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
|
|
|
634
645
|
},
|
|
635
646
|
name: RULE_NAME6,
|
|
636
647
|
create(context) {
|
|
648
|
+
if (!context.sourceCode.text.includes("use")) return {};
|
|
637
649
|
const alias = decodeSettings(context.settings).additionalHooks?.useState ?? [];
|
|
638
650
|
return {
|
|
639
651
|
CallExpression(node) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-hooks-extra",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.2-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.1.0",
|
|
47
47
|
"@typescript-eslint/utils": "^8.1.0",
|
|
48
48
|
"ts-pattern": "^5.3.1",
|
|
49
|
-
"@eslint-react/
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/
|
|
52
|
-
"@eslint-react/
|
|
53
|
-
"@eslint-react/
|
|
54
|
-
"@eslint-react/
|
|
55
|
-
"@eslint-react/
|
|
49
|
+
"@eslint-react/ast": "1.10.2-beta.1",
|
|
50
|
+
"@eslint-react/jsx": "1.10.2-beta.1",
|
|
51
|
+
"@eslint-react/shared": "1.10.2-beta.1",
|
|
52
|
+
"@eslint-react/tools": "1.10.2-beta.1",
|
|
53
|
+
"@eslint-react/types": "1.10.2-beta.1",
|
|
54
|
+
"@eslint-react/var": "1.10.2-beta.1",
|
|
55
|
+
"@eslint-react/core": "1.10.2-beta.1"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/react": "^18.3.3",
|