eslint-plugin-react-hooks-extra 1.15.0-beta.0 → 1.15.0-beta.8
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.d.mts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +207 -39
- package/dist/index.mjs +206 -38
- package/package.json +12 -12
package/dist/index.d.mts
CHANGED
|
@@ -7,6 +7,7 @@ declare const _default: {
|
|
|
7
7
|
};
|
|
8
8
|
readonly rules: {
|
|
9
9
|
readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
|
+
readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseLayoutEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
11
|
readonly "no-redundant-custom-hook": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
11
12
|
readonly "no-unnecessary-use-callback": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseCallback", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
12
13
|
readonly "no-unnecessary-use-memo": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
@@ -15,8 +16,6 @@ declare const _default: {
|
|
|
15
16
|
readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
16
17
|
/** @deprecated Use `no-unnecessary-use-memo` instead */
|
|
17
18
|
readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
18
|
-
/** @deprecated Use `no-direct-set-state-in-use-effect` instead */
|
|
19
|
-
readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
20
19
|
};
|
|
21
20
|
};
|
|
22
21
|
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ declare const _default: {
|
|
|
7
7
|
};
|
|
8
8
|
readonly rules: {
|
|
9
9
|
readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
|
+
readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseLayoutEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
11
|
readonly "no-redundant-custom-hook": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
11
12
|
readonly "no-unnecessary-use-callback": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseCallback", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
12
13
|
readonly "no-unnecessary-use-memo": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
@@ -15,8 +16,6 @@ declare const _default: {
|
|
|
15
16
|
readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"noRedundantCustomHook", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
16
17
|
/** @deprecated Use `no-unnecessary-use-memo` instead */
|
|
17
18
|
readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnnecessaryUseMemo", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
18
|
-
/** @deprecated Use `no-direct-set-state-in-use-effect` instead */
|
|
19
|
-
readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"noDirectSetStateInUseEffect", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
20
19
|
};
|
|
21
20
|
};
|
|
22
21
|
|
package/dist/index.js
CHANGED
|
@@ -4,11 +4,10 @@ var AST2 = require('@eslint-react/ast');
|
|
|
4
4
|
var core = require('@eslint-react/core');
|
|
5
5
|
var shared = require('@eslint-react/shared');
|
|
6
6
|
var tools = require('@eslint-react/tools');
|
|
7
|
-
var
|
|
7
|
+
var VAR4 = require('@eslint-react/var');
|
|
8
8
|
var types = require('@typescript-eslint/types');
|
|
9
9
|
var tsPattern = require('ts-pattern');
|
|
10
10
|
var astUtils = require('@typescript-eslint/utils/ast-utils');
|
|
11
|
-
require('@typescript-eslint/utils');
|
|
12
11
|
|
|
13
12
|
function _interopNamespace(e) {
|
|
14
13
|
if (e && e.__esModule) return e;
|
|
@@ -29,17 +28,17 @@ function _interopNamespace(e) {
|
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
var AST2__namespace = /*#__PURE__*/_interopNamespace(AST2);
|
|
32
|
-
var
|
|
31
|
+
var VAR4__namespace = /*#__PURE__*/_interopNamespace(VAR4);
|
|
33
32
|
|
|
34
33
|
// package.json
|
|
35
34
|
var name = "eslint-plugin-react-hooks-extra";
|
|
36
|
-
var version = "1.15.0-beta.
|
|
35
|
+
var version = "1.15.0-beta.8";
|
|
37
36
|
var createRule = shared.createRuleForPlugin("hooks-extra");
|
|
38
37
|
function isFromHookCall(name2, context, settings, predicate = tools.F.constTrue) {
|
|
39
38
|
const hookAlias = settings.additionalHooks?.[name2] ?? [];
|
|
40
39
|
return (topLevelId) => tools.F.pipe(
|
|
41
|
-
|
|
42
|
-
tools.O.flatMap(
|
|
40
|
+
VAR4__namespace.findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
|
|
41
|
+
tools.O.flatMap(VAR4__namespace.getVariableNode(0)),
|
|
43
42
|
tools.O.filter(AST2__namespace.is(types.AST_NODE_TYPES.CallExpression)),
|
|
44
43
|
tools.O.filter(core.isReactHookCallWithNameAlias(name2, context, hookAlias)),
|
|
45
44
|
tools.O.exists((call) => predicate(topLevelId, call))
|
|
@@ -132,17 +131,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
132
131
|
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
133
132
|
const settings = shared.decodeSettings(context.settings);
|
|
134
133
|
const additionalHooks = settings.additionalHooks ?? {};
|
|
135
|
-
const isUseEffectLikeCall = core.isReactHookCallWithNameAlias(
|
|
136
|
-
"useEffect",
|
|
137
|
-
context,
|
|
138
|
-
[
|
|
139
|
-
"useLayoutEffect",
|
|
140
|
-
"useInsertionEffect",
|
|
141
|
-
...additionalHooks.useEffect ?? [],
|
|
142
|
-
...additionalHooks.useLayoutEffect ?? [],
|
|
143
|
-
...additionalHooks.useInsertionEffect ?? []
|
|
144
|
-
]
|
|
145
|
-
);
|
|
134
|
+
const isUseEffectLikeCall = core.isReactHookCallWithNameAlias("useEffect", context, additionalHooks.useEffect ?? []);
|
|
146
135
|
const isUseStateCall2 = core.isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
|
|
147
136
|
const isUseMemoCall2 = core.isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
|
|
148
137
|
const isUseCallbackCall2 = core.isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
|
|
@@ -250,7 +239,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
250
239
|
},
|
|
251
240
|
"Program:exit"() {
|
|
252
241
|
const getSetStateCalls = (id, initialScope) => {
|
|
253
|
-
const node = tools.O.flatMap(
|
|
242
|
+
const node = tools.O.flatMap(VAR4__namespace.findVariable(id, initialScope), VAR4__namespace.getVariableNode(0)).pipe(tools.O.getOrNull);
|
|
254
243
|
switch (node?.type) {
|
|
255
244
|
case types.AST_NODE_TYPES.FunctionDeclaration:
|
|
256
245
|
case types.AST_NODE_TYPES.FunctionExpression:
|
|
@@ -301,7 +290,187 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
301
290
|
},
|
|
302
291
|
defaultOptions: []
|
|
303
292
|
});
|
|
304
|
-
var RULE_NAME2 = "no-
|
|
293
|
+
var RULE_NAME2 = "no-direct-set-state-in-use-layout-effect";
|
|
294
|
+
var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
295
|
+
meta: {
|
|
296
|
+
type: "problem",
|
|
297
|
+
docs: {
|
|
298
|
+
description: "disallow direct calls to the 'set' function of 'useState' in 'useLayoutEffect'"
|
|
299
|
+
},
|
|
300
|
+
messages: {
|
|
301
|
+
noDirectSetStateInUseLayoutEffect: "Do not call the 'set' function '{{name}}' of 'useState' directly in 'useLayoutEffect'."
|
|
302
|
+
},
|
|
303
|
+
schema: []
|
|
304
|
+
},
|
|
305
|
+
name: RULE_NAME2,
|
|
306
|
+
create(context) {
|
|
307
|
+
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
308
|
+
const settings = shared.decodeSettings(context.settings);
|
|
309
|
+
const additionalHooks = settings.additionalHooks ?? {};
|
|
310
|
+
const isUseEffectLikeCall = core.isReactHookCallWithNameAlias(
|
|
311
|
+
"useLayoutEffect",
|
|
312
|
+
context,
|
|
313
|
+
additionalHooks.useLayoutEffect ?? []
|
|
314
|
+
);
|
|
315
|
+
const isUseStateCall2 = core.isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
|
|
316
|
+
const isUseMemoCall2 = core.isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
|
|
317
|
+
const isUseCallbackCall2 = core.isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
|
|
318
|
+
const isSetStateCall = isSetFunctionCall(context, settings);
|
|
319
|
+
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
320
|
+
const functionStack = [];
|
|
321
|
+
const setupFunctionRef = tools.MutRef.make(null);
|
|
322
|
+
const setupFunctionIdentifiers = [];
|
|
323
|
+
const indirectFunctionCalls = [];
|
|
324
|
+
const indirectSetStateCalls = /* @__PURE__ */ new WeakMap();
|
|
325
|
+
const indirectSetStateCallsAsArgs = /* @__PURE__ */ new WeakMap();
|
|
326
|
+
const indirectSetStateCallsAsSetups = /* @__PURE__ */ new Map();
|
|
327
|
+
const indirectSetStateCallsInHooks = /* @__PURE__ */ new WeakMap();
|
|
328
|
+
const onSetupFunctionEnter = (node) => {
|
|
329
|
+
tools.MutRef.set(setupFunctionRef, node);
|
|
330
|
+
};
|
|
331
|
+
const onSetupFunctionExit = (node) => {
|
|
332
|
+
tools.MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
|
|
333
|
+
};
|
|
334
|
+
function isSetupFunction(node) {
|
|
335
|
+
return node.parent?.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectLikeCall(node.parent);
|
|
336
|
+
}
|
|
337
|
+
function getCallKind(node) {
|
|
338
|
+
return tsPattern.match(node).when(isUseStateCall2, () => "useState").when(isUseEffectLikeCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
339
|
+
}
|
|
340
|
+
function getFunctionKind(node) {
|
|
341
|
+
return tsPattern.match(node).when(isSetupFunction, () => "setup").when(AST2__namespace.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
":function"(node) {
|
|
345
|
+
const functionKind = getFunctionKind(node);
|
|
346
|
+
functionStack.push([node, functionKind]);
|
|
347
|
+
if (functionKind === "setup") onSetupFunctionEnter(node);
|
|
348
|
+
},
|
|
349
|
+
":function:exit"(node) {
|
|
350
|
+
const [_, functionKind] = functionStack.at(-1) ?? [];
|
|
351
|
+
functionStack.pop();
|
|
352
|
+
if (functionKind === "setup") onSetupFunctionExit(node);
|
|
353
|
+
},
|
|
354
|
+
CallExpression(node) {
|
|
355
|
+
const effectFn = tools.MutRef.get(setupFunctionRef);
|
|
356
|
+
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
|
|
357
|
+
if (parentFn?.async) return;
|
|
358
|
+
tsPattern.match(getCallKind(node)).with("setState", () => {
|
|
359
|
+
if (!parentFn) return;
|
|
360
|
+
if (parentFn !== effectFn && parentFnKind !== "immediate") {
|
|
361
|
+
const maybeVd = AST2__namespace.traverseUpGuard(node, isVariableDeclaratorFromHookCall);
|
|
362
|
+
if (tools.O.isSome(maybeVd)) {
|
|
363
|
+
const vd = maybeVd.value;
|
|
364
|
+
const calls2 = indirectSetStateCallsInHooks.get(vd.init) ?? [];
|
|
365
|
+
indirectSetStateCallsInHooks.set(vd.init, [...calls2, node]);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const calls = indirectSetStateCalls.get(parentFn) ?? [];
|
|
369
|
+
indirectSetStateCalls.set(parentFn, [...calls, node]);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
context.report({
|
|
373
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
374
|
+
node,
|
|
375
|
+
data: { name: context.sourceCode.getText(node.callee) }
|
|
376
|
+
});
|
|
377
|
+
}).with("useLayoutEffect", () => {
|
|
378
|
+
const [firstArg] = node.arguments;
|
|
379
|
+
if (AST2__namespace.isFunction(firstArg)) return;
|
|
380
|
+
const identifiers = AST2__namespace.getNestedIdentifiers(node);
|
|
381
|
+
setupFunctionIdentifiers.push(...identifiers);
|
|
382
|
+
}).with("other", () => {
|
|
383
|
+
const isInSetupFunction = effectFn === parentFn;
|
|
384
|
+
if (!isInSetupFunction) return;
|
|
385
|
+
indirectFunctionCalls.push(node);
|
|
386
|
+
}).otherwise(tools.F.constVoid);
|
|
387
|
+
},
|
|
388
|
+
Identifier(node) {
|
|
389
|
+
if (node.parent.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee === node) return;
|
|
390
|
+
if (!isIdFromUseStateCall(node)) return;
|
|
391
|
+
switch (node.parent.type) {
|
|
392
|
+
case types.AST_NODE_TYPES.CallExpression: {
|
|
393
|
+
const [firstArg] = node.parent.arguments;
|
|
394
|
+
if (node !== firstArg) break;
|
|
395
|
+
if (isUseCallbackCall2(node.parent)) {
|
|
396
|
+
const maybeVd = AST2__namespace.traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
|
|
397
|
+
if (tools.O.isNone(maybeVd)) break;
|
|
398
|
+
const vd = maybeVd.value;
|
|
399
|
+
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
|
|
400
|
+
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
|
|
401
|
+
}
|
|
402
|
+
if (isUseEffectLikeCall(node.parent)) {
|
|
403
|
+
const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
|
|
404
|
+
indirectSetStateCallsAsSetups.set(node.parent, [...calls, node]);
|
|
405
|
+
}
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
case types.AST_NODE_TYPES.ArrowFunctionExpression: {
|
|
409
|
+
const parent = node.parent.parent;
|
|
410
|
+
if (parent.type !== types.AST_NODE_TYPES.CallExpression) break;
|
|
411
|
+
if (!isUseMemoCall2(parent)) break;
|
|
412
|
+
const maybeVd = AST2__namespace.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
|
|
413
|
+
if (tools.O.isNone(maybeVd)) break;
|
|
414
|
+
const vd = maybeVd.value;
|
|
415
|
+
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
|
|
416
|
+
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
"Program:exit"() {
|
|
421
|
+
const getSetStateCalls = (id, initialScope) => {
|
|
422
|
+
const node = tools.O.flatMap(VAR4__namespace.findVariable(id, initialScope), VAR4__namespace.getVariableNode(0)).pipe(tools.O.getOrNull);
|
|
423
|
+
switch (node?.type) {
|
|
424
|
+
case types.AST_NODE_TYPES.FunctionDeclaration:
|
|
425
|
+
case types.AST_NODE_TYPES.FunctionExpression:
|
|
426
|
+
case types.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
427
|
+
return indirectSetStateCalls.get(node) ?? [];
|
|
428
|
+
case types.AST_NODE_TYPES.CallExpression:
|
|
429
|
+
return indirectSetStateCallsInHooks.get(node) ?? indirectSetStateCallsAsArgs.get(node) ?? [];
|
|
430
|
+
}
|
|
431
|
+
return [];
|
|
432
|
+
};
|
|
433
|
+
for (const [_, calls] of indirectSetStateCallsAsSetups) {
|
|
434
|
+
for (const call of calls) {
|
|
435
|
+
context.report({
|
|
436
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
437
|
+
node: call,
|
|
438
|
+
data: { name: call.name }
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
for (const { callee } of indirectFunctionCalls) {
|
|
443
|
+
if (!("name" in callee)) continue;
|
|
444
|
+
const { name: name2 } = callee;
|
|
445
|
+
const setStateCalls = getSetStateCalls(name2, context.sourceCode.getScope(callee));
|
|
446
|
+
for (const setStateCall of setStateCalls) {
|
|
447
|
+
context.report({
|
|
448
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
449
|
+
node: setStateCall,
|
|
450
|
+
data: {
|
|
451
|
+
name: AST2__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
for (const id of setupFunctionIdentifiers) {
|
|
457
|
+
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
458
|
+
for (const setStateCall of setStateCalls) {
|
|
459
|
+
context.report({
|
|
460
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
461
|
+
node: setStateCall,
|
|
462
|
+
data: {
|
|
463
|
+
name: AST2__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
},
|
|
471
|
+
defaultOptions: []
|
|
472
|
+
});
|
|
473
|
+
var RULE_NAME3 = "no-redundant-custom-hook";
|
|
305
474
|
var no_redundant_custom_hook_default = createRule({
|
|
306
475
|
meta: {
|
|
307
476
|
type: "problem",
|
|
@@ -313,7 +482,7 @@ var no_redundant_custom_hook_default = createRule({
|
|
|
313
482
|
},
|
|
314
483
|
schema: []
|
|
315
484
|
},
|
|
316
|
-
name:
|
|
485
|
+
name: RULE_NAME3,
|
|
317
486
|
create(context) {
|
|
318
487
|
const { ctx, listeners } = core.useHookCollector();
|
|
319
488
|
return {
|
|
@@ -336,7 +505,7 @@ var no_redundant_custom_hook_default = createRule({
|
|
|
336
505
|
},
|
|
337
506
|
defaultOptions: []
|
|
338
507
|
});
|
|
339
|
-
var
|
|
508
|
+
var RULE_NAME4 = "no-unnecessary-use-callback";
|
|
340
509
|
var no_unnecessary_use_callback_default = createRule({
|
|
341
510
|
meta: {
|
|
342
511
|
type: "problem",
|
|
@@ -348,7 +517,7 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
348
517
|
},
|
|
349
518
|
schema: []
|
|
350
519
|
},
|
|
351
|
-
name:
|
|
520
|
+
name: RULE_NAME4,
|
|
352
521
|
create(context) {
|
|
353
522
|
if (!context.sourceCode.text.includes("use")) return {};
|
|
354
523
|
const alias = shared.decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
|
|
@@ -373,8 +542,8 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
373
542
|
const hasEmptyDeps = tools.F.pipe(
|
|
374
543
|
tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
|
|
375
544
|
return tools.F.pipe(
|
|
376
|
-
|
|
377
|
-
tools.O.flatMap(
|
|
545
|
+
VAR4__namespace.findVariable(n.name, initialScope),
|
|
546
|
+
tools.O.flatMap(VAR4__namespace.getVariableNode(0)),
|
|
378
547
|
tools.O.filter(AST2__namespace.is(types.AST_NODE_TYPES.ArrayExpression))
|
|
379
548
|
);
|
|
380
549
|
}).otherwise(tools.O.none),
|
|
@@ -396,13 +565,13 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
396
565
|
return tools.O.some(n);
|
|
397
566
|
}).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
|
|
398
567
|
return tools.F.pipe(
|
|
399
|
-
|
|
400
|
-
tools.O.flatMap(
|
|
568
|
+
VAR4__namespace.findVariable(n.name, initialScope),
|
|
569
|
+
tools.O.flatMap(VAR4__namespace.getVariableNode(0)),
|
|
401
570
|
tools.O.filter(AST2__namespace.isFunction)
|
|
402
571
|
);
|
|
403
572
|
}).otherwise(tools.O.none),
|
|
404
573
|
tools.O.map((n) => context.sourceCode.getScope(n)),
|
|
405
|
-
tools.O.map((s) =>
|
|
574
|
+
tools.O.map((s) => VAR4__namespace.getChidScopes(s).flatMap((x) => x.references)),
|
|
406
575
|
tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
|
|
407
576
|
);
|
|
408
577
|
if (isReferencedToComponentScope) return;
|
|
@@ -415,7 +584,7 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
415
584
|
},
|
|
416
585
|
defaultOptions: []
|
|
417
586
|
});
|
|
418
|
-
var
|
|
587
|
+
var RULE_NAME5 = "no-unnecessary-use-memo";
|
|
419
588
|
var no_unnecessary_use_memo_default = createRule({
|
|
420
589
|
meta: {
|
|
421
590
|
type: "problem",
|
|
@@ -427,7 +596,7 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
427
596
|
},
|
|
428
597
|
schema: []
|
|
429
598
|
},
|
|
430
|
-
name:
|
|
599
|
+
name: RULE_NAME5,
|
|
431
600
|
create(context) {
|
|
432
601
|
if (!context.sourceCode.text.includes("use")) return {};
|
|
433
602
|
const alias = shared.decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
|
|
@@ -452,8 +621,8 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
452
621
|
const hasEmptyDeps = tools.F.pipe(
|
|
453
622
|
tsPattern.match(deps).with({ type: types.AST_NODE_TYPES.ArrayExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
|
|
454
623
|
return tools.F.pipe(
|
|
455
|
-
|
|
456
|
-
tools.O.flatMap(
|
|
624
|
+
VAR4__namespace.findVariable(n.name, initialScope),
|
|
625
|
+
tools.O.flatMap(VAR4__namespace.getVariableNode(0)),
|
|
457
626
|
tools.O.filter(AST2__namespace.is(types.AST_NODE_TYPES.ArrayExpression))
|
|
458
627
|
);
|
|
459
628
|
}).otherwise(tools.O.none),
|
|
@@ -475,13 +644,13 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
475
644
|
return tools.O.some(n);
|
|
476
645
|
}).with({ type: types.AST_NODE_TYPES.FunctionExpression }, tools.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
|
|
477
646
|
return tools.F.pipe(
|
|
478
|
-
|
|
479
|
-
tools.O.flatMap(
|
|
647
|
+
VAR4__namespace.findVariable(n.name, initialScope),
|
|
648
|
+
tools.O.flatMap(VAR4__namespace.getVariableNode(0)),
|
|
480
649
|
tools.O.filter(AST2__namespace.isFunction)
|
|
481
650
|
);
|
|
482
651
|
}).otherwise(tools.O.none),
|
|
483
652
|
tools.O.map((n) => context.sourceCode.getScope(n)),
|
|
484
|
-
tools.O.map((s) =>
|
|
653
|
+
tools.O.map((s) => VAR4__namespace.getChidScopes(s).flatMap((x) => x.references)),
|
|
485
654
|
tools.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
|
|
486
655
|
);
|
|
487
656
|
if (isReferencedToComponentScope) return;
|
|
@@ -494,7 +663,7 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
494
663
|
},
|
|
495
664
|
defaultOptions: []
|
|
496
665
|
});
|
|
497
|
-
var
|
|
666
|
+
var RULE_NAME6 = "prefer-use-state-lazy-initialization";
|
|
498
667
|
var ALLOW_LIST = ["Boolean", "String", "Number"];
|
|
499
668
|
var prefer_use_state_lazy_initialization_default = createRule({
|
|
500
669
|
meta: {
|
|
@@ -507,7 +676,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
|
|
|
507
676
|
},
|
|
508
677
|
schema: []
|
|
509
678
|
},
|
|
510
|
-
name:
|
|
679
|
+
name: RULE_NAME6,
|
|
511
680
|
create(context) {
|
|
512
681
|
if (!context.sourceCode.text.includes("use")) return {};
|
|
513
682
|
const alias = shared.decodeSettings(context.settings).additionalHooks?.useState ?? [];
|
|
@@ -543,6 +712,7 @@ var src_default = {
|
|
|
543
712
|
},
|
|
544
713
|
rules: {
|
|
545
714
|
"no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
|
|
715
|
+
"no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_layout_effect_default,
|
|
546
716
|
"no-redundant-custom-hook": no_redundant_custom_hook_default,
|
|
547
717
|
"no-unnecessary-use-callback": no_unnecessary_use_callback_default,
|
|
548
718
|
"no-unnecessary-use-memo": no_unnecessary_use_memo_default,
|
|
@@ -551,9 +721,7 @@ var src_default = {
|
|
|
551
721
|
/** @deprecated Use `no-redundant-custom-hook` instead */
|
|
552
722
|
"ensure-custom-hooks-using-other-hooks": no_redundant_custom_hook_default,
|
|
553
723
|
/** @deprecated Use `no-unnecessary-use-memo` instead */
|
|
554
|
-
"ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default
|
|
555
|
-
/** @deprecated Use `no-direct-set-state-in-use-effect` instead */
|
|
556
|
-
"no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default
|
|
724
|
+
"ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default
|
|
557
725
|
}
|
|
558
726
|
};
|
|
559
727
|
|
package/dist/index.mjs
CHANGED
|
@@ -2,21 +2,20 @@ import * as AST2 from '@eslint-react/ast';
|
|
|
2
2
|
import { isReactHookCallWithNameAlias, useHookCollector, isReactHookCall, isUseCallbackCall, isReactHookCallWithNameLoose, isUseMemoCall, isUseStateCall, isReactHookName } from '@eslint-react/core';
|
|
3
3
|
import { createRuleForPlugin, decodeSettings } from '@eslint-react/shared';
|
|
4
4
|
import { MutRef, O, F } from '@eslint-react/tools';
|
|
5
|
-
import * as
|
|
5
|
+
import * as VAR4 from '@eslint-react/var';
|
|
6
6
|
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
7
7
|
import { match, isMatching } from 'ts-pattern';
|
|
8
8
|
import { getStaticValue } from '@typescript-eslint/utils/ast-utils';
|
|
9
|
-
import '@typescript-eslint/utils';
|
|
10
9
|
|
|
11
10
|
// package.json
|
|
12
11
|
var name = "eslint-plugin-react-hooks-extra";
|
|
13
|
-
var version = "1.15.0-beta.
|
|
12
|
+
var version = "1.15.0-beta.8";
|
|
14
13
|
var createRule = createRuleForPlugin("hooks-extra");
|
|
15
14
|
function isFromHookCall(name2, context, settings, predicate = F.constTrue) {
|
|
16
15
|
const hookAlias = settings.additionalHooks?.[name2] ?? [];
|
|
17
16
|
return (topLevelId) => F.pipe(
|
|
18
|
-
|
|
19
|
-
O.flatMap(
|
|
17
|
+
VAR4.findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
|
|
18
|
+
O.flatMap(VAR4.getVariableNode(0)),
|
|
20
19
|
O.filter(AST2.is(AST_NODE_TYPES.CallExpression)),
|
|
21
20
|
O.filter(isReactHookCallWithNameAlias(name2, context, hookAlias)),
|
|
22
21
|
O.exists((call) => predicate(topLevelId, call))
|
|
@@ -109,17 +108,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
109
108
|
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
110
109
|
const settings = decodeSettings(context.settings);
|
|
111
110
|
const additionalHooks = settings.additionalHooks ?? {};
|
|
112
|
-
const isUseEffectLikeCall = isReactHookCallWithNameAlias(
|
|
113
|
-
"useEffect",
|
|
114
|
-
context,
|
|
115
|
-
[
|
|
116
|
-
"useLayoutEffect",
|
|
117
|
-
"useInsertionEffect",
|
|
118
|
-
...additionalHooks.useEffect ?? [],
|
|
119
|
-
...additionalHooks.useLayoutEffect ?? [],
|
|
120
|
-
...additionalHooks.useInsertionEffect ?? []
|
|
121
|
-
]
|
|
122
|
-
);
|
|
111
|
+
const isUseEffectLikeCall = isReactHookCallWithNameAlias("useEffect", context, additionalHooks.useEffect ?? []);
|
|
123
112
|
const isUseStateCall2 = isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
|
|
124
113
|
const isUseMemoCall2 = isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
|
|
125
114
|
const isUseCallbackCall2 = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
|
|
@@ -227,7 +216,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
227
216
|
},
|
|
228
217
|
"Program:exit"() {
|
|
229
218
|
const getSetStateCalls = (id, initialScope) => {
|
|
230
|
-
const node = O.flatMap(
|
|
219
|
+
const node = O.flatMap(VAR4.findVariable(id, initialScope), VAR4.getVariableNode(0)).pipe(O.getOrNull);
|
|
231
220
|
switch (node?.type) {
|
|
232
221
|
case AST_NODE_TYPES.FunctionDeclaration:
|
|
233
222
|
case AST_NODE_TYPES.FunctionExpression:
|
|
@@ -278,7 +267,187 @@ var no_direct_set_state_in_use_effect_default = createRule({
|
|
|
278
267
|
},
|
|
279
268
|
defaultOptions: []
|
|
280
269
|
});
|
|
281
|
-
var RULE_NAME2 = "no-
|
|
270
|
+
var RULE_NAME2 = "no-direct-set-state-in-use-layout-effect";
|
|
271
|
+
var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
272
|
+
meta: {
|
|
273
|
+
type: "problem",
|
|
274
|
+
docs: {
|
|
275
|
+
description: "disallow direct calls to the 'set' function of 'useState' in 'useLayoutEffect'"
|
|
276
|
+
},
|
|
277
|
+
messages: {
|
|
278
|
+
noDirectSetStateInUseLayoutEffect: "Do not call the 'set' function '{{name}}' of 'useState' directly in 'useLayoutEffect'."
|
|
279
|
+
},
|
|
280
|
+
schema: []
|
|
281
|
+
},
|
|
282
|
+
name: RULE_NAME2,
|
|
283
|
+
create(context) {
|
|
284
|
+
if (!/use\w*Effect/u.test(context.sourceCode.text)) return {};
|
|
285
|
+
const settings = decodeSettings(context.settings);
|
|
286
|
+
const additionalHooks = settings.additionalHooks ?? {};
|
|
287
|
+
const isUseEffectLikeCall = isReactHookCallWithNameAlias(
|
|
288
|
+
"useLayoutEffect",
|
|
289
|
+
context,
|
|
290
|
+
additionalHooks.useLayoutEffect ?? []
|
|
291
|
+
);
|
|
292
|
+
const isUseStateCall2 = isReactHookCallWithNameAlias("useState", context, additionalHooks.useState ?? []);
|
|
293
|
+
const isUseMemoCall2 = isReactHookCallWithNameAlias("useMemo", context, additionalHooks.useMemo ?? []);
|
|
294
|
+
const isUseCallbackCall2 = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
|
|
295
|
+
const isSetStateCall = isSetFunctionCall(context, settings);
|
|
296
|
+
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
|
|
297
|
+
const functionStack = [];
|
|
298
|
+
const setupFunctionRef = MutRef.make(null);
|
|
299
|
+
const setupFunctionIdentifiers = [];
|
|
300
|
+
const indirectFunctionCalls = [];
|
|
301
|
+
const indirectSetStateCalls = /* @__PURE__ */ new WeakMap();
|
|
302
|
+
const indirectSetStateCallsAsArgs = /* @__PURE__ */ new WeakMap();
|
|
303
|
+
const indirectSetStateCallsAsSetups = /* @__PURE__ */ new Map();
|
|
304
|
+
const indirectSetStateCallsInHooks = /* @__PURE__ */ new WeakMap();
|
|
305
|
+
const onSetupFunctionEnter = (node) => {
|
|
306
|
+
MutRef.set(setupFunctionRef, node);
|
|
307
|
+
};
|
|
308
|
+
const onSetupFunctionExit = (node) => {
|
|
309
|
+
MutRef.update(setupFunctionRef, (current) => current === node ? null : current);
|
|
310
|
+
};
|
|
311
|
+
function isSetupFunction(node) {
|
|
312
|
+
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectLikeCall(node.parent);
|
|
313
|
+
}
|
|
314
|
+
function getCallKind(node) {
|
|
315
|
+
return match(node).when(isUseStateCall2, () => "useState").when(isUseEffectLikeCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
|
|
316
|
+
}
|
|
317
|
+
function getFunctionKind(node) {
|
|
318
|
+
return match(node).when(isSetupFunction, () => "setup").when(AST2.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
":function"(node) {
|
|
322
|
+
const functionKind = getFunctionKind(node);
|
|
323
|
+
functionStack.push([node, functionKind]);
|
|
324
|
+
if (functionKind === "setup") onSetupFunctionEnter(node);
|
|
325
|
+
},
|
|
326
|
+
":function:exit"(node) {
|
|
327
|
+
const [_, functionKind] = functionStack.at(-1) ?? [];
|
|
328
|
+
functionStack.pop();
|
|
329
|
+
if (functionKind === "setup") onSetupFunctionExit(node);
|
|
330
|
+
},
|
|
331
|
+
CallExpression(node) {
|
|
332
|
+
const effectFn = MutRef.get(setupFunctionRef);
|
|
333
|
+
const [parentFn, parentFnKind] = functionStack.at(-1) ?? [];
|
|
334
|
+
if (parentFn?.async) return;
|
|
335
|
+
match(getCallKind(node)).with("setState", () => {
|
|
336
|
+
if (!parentFn) return;
|
|
337
|
+
if (parentFn !== effectFn && parentFnKind !== "immediate") {
|
|
338
|
+
const maybeVd = AST2.traverseUpGuard(node, isVariableDeclaratorFromHookCall);
|
|
339
|
+
if (O.isSome(maybeVd)) {
|
|
340
|
+
const vd = maybeVd.value;
|
|
341
|
+
const calls2 = indirectSetStateCallsInHooks.get(vd.init) ?? [];
|
|
342
|
+
indirectSetStateCallsInHooks.set(vd.init, [...calls2, node]);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const calls = indirectSetStateCalls.get(parentFn) ?? [];
|
|
346
|
+
indirectSetStateCalls.set(parentFn, [...calls, node]);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
context.report({
|
|
350
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
351
|
+
node,
|
|
352
|
+
data: { name: context.sourceCode.getText(node.callee) }
|
|
353
|
+
});
|
|
354
|
+
}).with("useLayoutEffect", () => {
|
|
355
|
+
const [firstArg] = node.arguments;
|
|
356
|
+
if (AST2.isFunction(firstArg)) return;
|
|
357
|
+
const identifiers = AST2.getNestedIdentifiers(node);
|
|
358
|
+
setupFunctionIdentifiers.push(...identifiers);
|
|
359
|
+
}).with("other", () => {
|
|
360
|
+
const isInSetupFunction = effectFn === parentFn;
|
|
361
|
+
if (!isInSetupFunction) return;
|
|
362
|
+
indirectFunctionCalls.push(node);
|
|
363
|
+
}).otherwise(F.constVoid);
|
|
364
|
+
},
|
|
365
|
+
Identifier(node) {
|
|
366
|
+
if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) return;
|
|
367
|
+
if (!isIdFromUseStateCall(node)) return;
|
|
368
|
+
switch (node.parent.type) {
|
|
369
|
+
case AST_NODE_TYPES.CallExpression: {
|
|
370
|
+
const [firstArg] = node.parent.arguments;
|
|
371
|
+
if (node !== firstArg) break;
|
|
372
|
+
if (isUseCallbackCall2(node.parent)) {
|
|
373
|
+
const maybeVd = AST2.traverseUpGuard(node.parent, isVariableDeclaratorFromHookCall);
|
|
374
|
+
if (O.isNone(maybeVd)) break;
|
|
375
|
+
const vd = maybeVd.value;
|
|
376
|
+
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
|
|
377
|
+
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
|
|
378
|
+
}
|
|
379
|
+
if (isUseEffectLikeCall(node.parent)) {
|
|
380
|
+
const calls = indirectSetStateCallsAsArgs.get(node.parent) ?? [];
|
|
381
|
+
indirectSetStateCallsAsSetups.set(node.parent, [...calls, node]);
|
|
382
|
+
}
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
case AST_NODE_TYPES.ArrowFunctionExpression: {
|
|
386
|
+
const parent = node.parent.parent;
|
|
387
|
+
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
|
|
388
|
+
if (!isUseMemoCall2(parent)) break;
|
|
389
|
+
const maybeVd = AST2.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
|
|
390
|
+
if (O.isNone(maybeVd)) break;
|
|
391
|
+
const vd = maybeVd.value;
|
|
392
|
+
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
|
|
393
|
+
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
"Program:exit"() {
|
|
398
|
+
const getSetStateCalls = (id, initialScope) => {
|
|
399
|
+
const node = O.flatMap(VAR4.findVariable(id, initialScope), VAR4.getVariableNode(0)).pipe(O.getOrNull);
|
|
400
|
+
switch (node?.type) {
|
|
401
|
+
case AST_NODE_TYPES.FunctionDeclaration:
|
|
402
|
+
case AST_NODE_TYPES.FunctionExpression:
|
|
403
|
+
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
404
|
+
return indirectSetStateCalls.get(node) ?? [];
|
|
405
|
+
case AST_NODE_TYPES.CallExpression:
|
|
406
|
+
return indirectSetStateCallsInHooks.get(node) ?? indirectSetStateCallsAsArgs.get(node) ?? [];
|
|
407
|
+
}
|
|
408
|
+
return [];
|
|
409
|
+
};
|
|
410
|
+
for (const [_, calls] of indirectSetStateCallsAsSetups) {
|
|
411
|
+
for (const call of calls) {
|
|
412
|
+
context.report({
|
|
413
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
414
|
+
node: call,
|
|
415
|
+
data: { name: call.name }
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
for (const { callee } of indirectFunctionCalls) {
|
|
420
|
+
if (!("name" in callee)) continue;
|
|
421
|
+
const { name: name2 } = callee;
|
|
422
|
+
const setStateCalls = getSetStateCalls(name2, context.sourceCode.getScope(callee));
|
|
423
|
+
for (const setStateCall of setStateCalls) {
|
|
424
|
+
context.report({
|
|
425
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
426
|
+
node: setStateCall,
|
|
427
|
+
data: {
|
|
428
|
+
name: AST2.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
for (const id of setupFunctionIdentifiers) {
|
|
434
|
+
const setStateCalls = getSetStateCalls(id.name, context.sourceCode.getScope(id));
|
|
435
|
+
for (const setStateCall of setStateCalls) {
|
|
436
|
+
context.report({
|
|
437
|
+
messageId: "noDirectSetStateInUseLayoutEffect",
|
|
438
|
+
node: setStateCall,
|
|
439
|
+
data: {
|
|
440
|
+
name: AST2.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
},
|
|
448
|
+
defaultOptions: []
|
|
449
|
+
});
|
|
450
|
+
var RULE_NAME3 = "no-redundant-custom-hook";
|
|
282
451
|
var no_redundant_custom_hook_default = createRule({
|
|
283
452
|
meta: {
|
|
284
453
|
type: "problem",
|
|
@@ -290,7 +459,7 @@ var no_redundant_custom_hook_default = createRule({
|
|
|
290
459
|
},
|
|
291
460
|
schema: []
|
|
292
461
|
},
|
|
293
|
-
name:
|
|
462
|
+
name: RULE_NAME3,
|
|
294
463
|
create(context) {
|
|
295
464
|
const { ctx, listeners } = useHookCollector();
|
|
296
465
|
return {
|
|
@@ -313,7 +482,7 @@ var no_redundant_custom_hook_default = createRule({
|
|
|
313
482
|
},
|
|
314
483
|
defaultOptions: []
|
|
315
484
|
});
|
|
316
|
-
var
|
|
485
|
+
var RULE_NAME4 = "no-unnecessary-use-callback";
|
|
317
486
|
var no_unnecessary_use_callback_default = createRule({
|
|
318
487
|
meta: {
|
|
319
488
|
type: "problem",
|
|
@@ -325,7 +494,7 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
325
494
|
},
|
|
326
495
|
schema: []
|
|
327
496
|
},
|
|
328
|
-
name:
|
|
497
|
+
name: RULE_NAME4,
|
|
329
498
|
create(context) {
|
|
330
499
|
if (!context.sourceCode.text.includes("use")) return {};
|
|
331
500
|
const alias = decodeSettings(context.settings).additionalHooks?.useCallback ?? [];
|
|
@@ -350,8 +519,8 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
350
519
|
const hasEmptyDeps = F.pipe(
|
|
351
520
|
match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
352
521
|
return F.pipe(
|
|
353
|
-
|
|
354
|
-
O.flatMap(
|
|
522
|
+
VAR4.findVariable(n.name, initialScope),
|
|
523
|
+
O.flatMap(VAR4.getVariableNode(0)),
|
|
355
524
|
O.filter(AST2.is(AST_NODE_TYPES.ArrayExpression))
|
|
356
525
|
);
|
|
357
526
|
}).otherwise(O.none),
|
|
@@ -373,13 +542,13 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
373
542
|
return O.some(n);
|
|
374
543
|
}).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
375
544
|
return F.pipe(
|
|
376
|
-
|
|
377
|
-
O.flatMap(
|
|
545
|
+
VAR4.findVariable(n.name, initialScope),
|
|
546
|
+
O.flatMap(VAR4.getVariableNode(0)),
|
|
378
547
|
O.filter(AST2.isFunction)
|
|
379
548
|
);
|
|
380
549
|
}).otherwise(O.none),
|
|
381
550
|
O.map((n) => context.sourceCode.getScope(n)),
|
|
382
|
-
O.map((s) =>
|
|
551
|
+
O.map((s) => VAR4.getChidScopes(s).flatMap((x) => x.references)),
|
|
383
552
|
O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
|
|
384
553
|
);
|
|
385
554
|
if (isReferencedToComponentScope) return;
|
|
@@ -392,7 +561,7 @@ var no_unnecessary_use_callback_default = createRule({
|
|
|
392
561
|
},
|
|
393
562
|
defaultOptions: []
|
|
394
563
|
});
|
|
395
|
-
var
|
|
564
|
+
var RULE_NAME5 = "no-unnecessary-use-memo";
|
|
396
565
|
var no_unnecessary_use_memo_default = createRule({
|
|
397
566
|
meta: {
|
|
398
567
|
type: "problem",
|
|
@@ -404,7 +573,7 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
404
573
|
},
|
|
405
574
|
schema: []
|
|
406
575
|
},
|
|
407
|
-
name:
|
|
576
|
+
name: RULE_NAME5,
|
|
408
577
|
create(context) {
|
|
409
578
|
if (!context.sourceCode.text.includes("use")) return {};
|
|
410
579
|
const alias = decodeSettings(context.settings).additionalHooks?.useMemo ?? [];
|
|
@@ -429,8 +598,8 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
429
598
|
const hasEmptyDeps = F.pipe(
|
|
430
599
|
match(deps).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
431
600
|
return F.pipe(
|
|
432
|
-
|
|
433
|
-
O.flatMap(
|
|
601
|
+
VAR4.findVariable(n.name, initialScope),
|
|
602
|
+
O.flatMap(VAR4.getVariableNode(0)),
|
|
434
603
|
O.filter(AST2.is(AST_NODE_TYPES.ArrayExpression))
|
|
435
604
|
);
|
|
436
605
|
}).otherwise(O.none),
|
|
@@ -452,13 +621,13 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
452
621
|
return O.some(n);
|
|
453
622
|
}).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
|
|
454
623
|
return F.pipe(
|
|
455
|
-
|
|
456
|
-
O.flatMap(
|
|
624
|
+
VAR4.findVariable(n.name, initialScope),
|
|
625
|
+
O.flatMap(VAR4.getVariableNode(0)),
|
|
457
626
|
O.filter(AST2.isFunction)
|
|
458
627
|
);
|
|
459
628
|
}).otherwise(O.none),
|
|
460
629
|
O.map((n) => context.sourceCode.getScope(n)),
|
|
461
|
-
O.map((s) =>
|
|
630
|
+
O.map((s) => VAR4.getChidScopes(s).flatMap((x) => x.references)),
|
|
462
631
|
O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
|
|
463
632
|
);
|
|
464
633
|
if (isReferencedToComponentScope) return;
|
|
@@ -471,7 +640,7 @@ var no_unnecessary_use_memo_default = createRule({
|
|
|
471
640
|
},
|
|
472
641
|
defaultOptions: []
|
|
473
642
|
});
|
|
474
|
-
var
|
|
643
|
+
var RULE_NAME6 = "prefer-use-state-lazy-initialization";
|
|
475
644
|
var ALLOW_LIST = ["Boolean", "String", "Number"];
|
|
476
645
|
var prefer_use_state_lazy_initialization_default = createRule({
|
|
477
646
|
meta: {
|
|
@@ -484,7 +653,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
|
|
|
484
653
|
},
|
|
485
654
|
schema: []
|
|
486
655
|
},
|
|
487
|
-
name:
|
|
656
|
+
name: RULE_NAME6,
|
|
488
657
|
create(context) {
|
|
489
658
|
if (!context.sourceCode.text.includes("use")) return {};
|
|
490
659
|
const alias = decodeSettings(context.settings).additionalHooks?.useState ?? [];
|
|
@@ -520,6 +689,7 @@ var src_default = {
|
|
|
520
689
|
},
|
|
521
690
|
rules: {
|
|
522
691
|
"no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
|
|
692
|
+
"no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_layout_effect_default,
|
|
523
693
|
"no-redundant-custom-hook": no_redundant_custom_hook_default,
|
|
524
694
|
"no-unnecessary-use-callback": no_unnecessary_use_callback_default,
|
|
525
695
|
"no-unnecessary-use-memo": no_unnecessary_use_memo_default,
|
|
@@ -528,9 +698,7 @@ var src_default = {
|
|
|
528
698
|
/** @deprecated Use `no-redundant-custom-hook` instead */
|
|
529
699
|
"ensure-custom-hooks-using-other-hooks": no_redundant_custom_hook_default,
|
|
530
700
|
/** @deprecated Use `no-unnecessary-use-memo` instead */
|
|
531
|
-
"ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default
|
|
532
|
-
/** @deprecated Use `no-direct-set-state-in-use-effect` instead */
|
|
533
|
-
"no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_effect_default
|
|
701
|
+
"ensure-use-memo-has-non-empty-deps": no_unnecessary_use_memo_default
|
|
534
702
|
}
|
|
535
703
|
};
|
|
536
704
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-hooks-extra",
|
|
3
|
-
"version": "1.15.0-beta.
|
|
3
|
+
"version": "1.15.0-beta.8",
|
|
4
4
|
"description": "ESLint React's ESLint plugin for React Hooks related rules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -41,18 +41,18 @@
|
|
|
41
41
|
"./package.json"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@typescript-eslint/scope-manager": "^8.8.
|
|
45
|
-
"@typescript-eslint/type-utils": "^8.8.
|
|
46
|
-
"@typescript-eslint/types": "^8.8.
|
|
47
|
-
"@typescript-eslint/utils": "^8.8.
|
|
44
|
+
"@typescript-eslint/scope-manager": "^8.8.1",
|
|
45
|
+
"@typescript-eslint/type-utils": "^8.8.1",
|
|
46
|
+
"@typescript-eslint/types": "^8.8.1",
|
|
47
|
+
"@typescript-eslint/utils": "^8.8.1",
|
|
48
48
|
"ts-pattern": "^5.4.0",
|
|
49
|
-
"@eslint-react/ast": "1.15.0-beta.
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/
|
|
52
|
-
"@eslint-react/
|
|
53
|
-
"@eslint-react/
|
|
54
|
-
"@eslint-react/var": "1.15.0-beta.
|
|
55
|
-
"@eslint-react/
|
|
49
|
+
"@eslint-react/ast": "1.15.0-beta.8",
|
|
50
|
+
"@eslint-react/jsx": "1.15.0-beta.8",
|
|
51
|
+
"@eslint-react/core": "1.15.0-beta.8",
|
|
52
|
+
"@eslint-react/shared": "1.15.0-beta.8",
|
|
53
|
+
"@eslint-react/tools": "1.15.0-beta.8",
|
|
54
|
+
"@eslint-react/var": "1.15.0-beta.8",
|
|
55
|
+
"@eslint-react/types": "1.15.0-beta.8"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/react": "^18.3.11",
|