eslint-plugin-react-hooks-extra 1.5.25 → 1.5.26-beta.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/README.md +10 -7
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +225 -20
- package/dist/index.mjs +227 -22
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -30,7 +30,8 @@ export default [
|
|
|
30
30
|
"react-hooks-extra": reactHooksExtra,
|
|
31
31
|
rules: {
|
|
32
32
|
// react-hooks-extra recommended rules
|
|
33
|
-
"react-hooks-extra/
|
|
33
|
+
"react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
|
|
34
|
+
"react-hooks-extra/no-direct-set-state-in-use-layout-effect": "warn",
|
|
34
35
|
"react-hooks-extra/prefer-use-state-lazy-initialization": "warn",
|
|
35
36
|
}
|
|
36
37
|
],
|
|
@@ -40,9 +41,11 @@ export default [
|
|
|
40
41
|
|
|
41
42
|
## Rules
|
|
42
43
|
|
|
43
|
-
| Rule
|
|
44
|
-
|
|
|
45
|
-
| `ensure-custom-hooks-using-other-hooks`
|
|
46
|
-
| `ensure-use-callback-has-non-empty-deps`
|
|
47
|
-
| `ensure-use-memo-has-non-empty-deps`
|
|
48
|
-
| `
|
|
44
|
+
| Rule | Description | 💼 | 💭 | ❌ |
|
|
45
|
+
| :----------------------------------------- | :------------------------------------------------------------------------------ | :-: | :-: | :-: |
|
|
46
|
+
| `ensure-custom-hooks-using-other-hooks` | Warns when custom Hooks that don't use other Hooks. | ✔️ | | |
|
|
47
|
+
| `ensure-use-callback-has-non-empty-deps` | Warns when `useCallback` is called with empty dependencies array. | 🧐 | | |
|
|
48
|
+
| `ensure-use-memo-has-non-empty-deps` | Warns when `useMemo` is called with empty dependencies array. | 🧐 | | |
|
|
49
|
+
| `no-direct-set-state-in-use-effect` | Disallow direct calls to the `set` function of `useState` in `useEffect`. | ✔️ | | |
|
|
50
|
+
| `no-direct-set-state-in-use-layout-effect` | Disallow direct calls to the `set` function of `useState` in `useLayoutEffect`. | ✔️ | | |
|
|
51
|
+
| `prefer-use-state-lazy-initialization` | Warns function calls made inside `useState` calls. | 🚀 | | |
|
package/dist/index.d.mts
CHANGED
|
@@ -8,6 +8,8 @@ declare const rules: {
|
|
|
8
8
|
readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
9
9
|
readonly "ensure-use-callback-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
10
|
readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
11
|
+
readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_EFFECT", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
12
|
+
readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
11
13
|
readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"PREFER_USE_STATE_LAZY_INITIALIZATION", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
12
14
|
};
|
|
13
15
|
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ declare const rules: {
|
|
|
8
8
|
readonly "ensure-custom-hooks-using-other-hooks": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_CUSTOM_HOOKS_USING_OTHER_HOOKS", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
9
9
|
readonly "ensure-use-callback-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
10
|
readonly "ensure-use-memo-has-non-empty-deps": _typescript_eslint_utils_ts_eslint.RuleModule<"ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
11
|
+
readonly "no-direct-set-state-in-use-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_EFFECT", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
12
|
+
readonly "no-direct-set-state-in-use-layout-effect": _typescript_eslint_utils_ts_eslint.RuleModule<"NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
11
13
|
readonly "prefer-use-state-lazy-initialization": _typescript_eslint_utils_ts_eslint.RuleModule<"PREFER_USE_STATE_LAZY_INITIALIZATION", [], _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
12
14
|
};
|
|
13
15
|
|
package/dist/index.js
CHANGED
|
@@ -5,10 +5,11 @@ var shared = require('@eslint-react/shared');
|
|
|
5
5
|
var ast = require('@eslint-react/ast');
|
|
6
6
|
var tools = require('@eslint-react/tools');
|
|
7
7
|
var _var = require('@eslint-react/var');
|
|
8
|
+
var astUtils = require('@typescript-eslint/utils/ast-utils');
|
|
8
9
|
|
|
9
10
|
// package.json
|
|
10
11
|
var name = "eslint-plugin-react-hooks-extra";
|
|
11
|
-
var version = "1.5.
|
|
12
|
+
var version = "1.5.26-beta.2";
|
|
12
13
|
var createRule = shared.createRuleForPlugin("hooks-extra");
|
|
13
14
|
|
|
14
15
|
// src/rules/ensure-custom-hooks-using-other-hooks.ts
|
|
@@ -226,7 +227,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
226
227
|
description: "enforce 'useCallback' has non-empty dependencies array"
|
|
227
228
|
},
|
|
228
229
|
messages: {
|
|
229
|
-
ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS: "An useCallback should have a non-empty dependencies array."
|
|
230
|
+
ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS: "An 'useCallback' should have a non-empty dependencies array."
|
|
230
231
|
},
|
|
231
232
|
schema: []
|
|
232
233
|
},
|
|
@@ -235,12 +236,15 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
235
236
|
const alias = shared.getESLintReactSettings(context.settings).additionalHooks?.useCallback ?? [];
|
|
236
237
|
return {
|
|
237
238
|
CallExpression(node) {
|
|
238
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
239
239
|
if (!core.isReactHookCall(node)) return;
|
|
240
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
240
241
|
if (!core.isUseCallbackCall(node, context) && !alias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node))) {
|
|
241
242
|
return;
|
|
242
243
|
}
|
|
243
|
-
const
|
|
244
|
+
const scope = context.sourceCode.getScope(node);
|
|
245
|
+
const component = scope.block;
|
|
246
|
+
if (!ast.isFunction(component)) return;
|
|
247
|
+
const [cb, deps] = node.arguments;
|
|
244
248
|
if (!deps) {
|
|
245
249
|
context.report({
|
|
246
250
|
messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
|
|
@@ -248,7 +252,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
248
252
|
});
|
|
249
253
|
return;
|
|
250
254
|
}
|
|
251
|
-
const
|
|
255
|
+
const hasEmptyDeps = tools.F.pipe(
|
|
252
256
|
$(deps).with({ type: ast.NodeType.ArrayExpression }, tools.O.some).with({ type: ast.NodeType.Identifier }, (n2) => {
|
|
253
257
|
return tools.F.pipe(
|
|
254
258
|
_var.findVariable(n2.name, initialScope),
|
|
@@ -256,13 +260,32 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
256
260
|
tools.O.filter(ast.is(ast.NodeType.ArrayExpression))
|
|
257
261
|
);
|
|
258
262
|
}).otherwise(tools.O.none),
|
|
259
|
-
tools.O.
|
|
260
|
-
|
|
263
|
+
tools.O.exists((x2) => x2.elements.length === 0)
|
|
264
|
+
);
|
|
265
|
+
if (!hasEmptyDeps) return;
|
|
266
|
+
if (!cb) {
|
|
267
|
+
context.report({
|
|
261
268
|
messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
|
|
262
269
|
node
|
|
263
|
-
})
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const isReferencedToComponentScope = tools.F.pipe(
|
|
274
|
+
$(cb).with({ type: ast.NodeType.ArrowFunctionExpression }, tools.O.some).with({ type: ast.NodeType.FunctionExpression }, tools.O.some).with({ type: ast.NodeType.Identifier }, (n2) => {
|
|
275
|
+
return tools.F.pipe(
|
|
276
|
+
_var.findVariable(n2.name, initialScope),
|
|
277
|
+
tools.O.flatMap(_var.getVariableInit(0)),
|
|
278
|
+
tools.O.filter(ast.isFunction)
|
|
279
|
+
);
|
|
280
|
+
}).otherwise(tools.O.none),
|
|
281
|
+
tools.O.map((n2) => context.sourceCode.getScope(n2).references),
|
|
282
|
+
tools.O.exists((refs) => refs.some((x2) => x2.resolved?.scope.block === component))
|
|
264
283
|
);
|
|
265
|
-
|
|
284
|
+
if (isReferencedToComponentScope) return;
|
|
285
|
+
context.report({
|
|
286
|
+
messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
|
|
287
|
+
node
|
|
288
|
+
});
|
|
266
289
|
}
|
|
267
290
|
};
|
|
268
291
|
},
|
|
@@ -276,7 +299,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
276
299
|
description: "enforce 'useMemo' has non-empty dependencies array"
|
|
277
300
|
},
|
|
278
301
|
messages: {
|
|
279
|
-
ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS: "An useMemo should have a non-empty dependencies array."
|
|
302
|
+
ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS: "An 'useMemo' should have a non-empty dependencies array."
|
|
280
303
|
},
|
|
281
304
|
schema: []
|
|
282
305
|
},
|
|
@@ -285,10 +308,15 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
285
308
|
const alias = shared.getESLintReactSettings(context.settings).additionalHooks?.useMemo ?? [];
|
|
286
309
|
return {
|
|
287
310
|
CallExpression(node) {
|
|
288
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
289
311
|
if (!core.isReactHookCall(node)) return;
|
|
290
|
-
|
|
291
|
-
|
|
312
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
313
|
+
if (!core.isUseMemoCall(node, context) && !alias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node))) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const scope = context.sourceCode.getScope(node);
|
|
317
|
+
const component = scope.block;
|
|
318
|
+
if (!ast.isFunction(component)) return;
|
|
319
|
+
const [cb, deps] = node.arguments;
|
|
292
320
|
if (!deps) {
|
|
293
321
|
context.report({
|
|
294
322
|
messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
|
|
@@ -296,7 +324,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
296
324
|
});
|
|
297
325
|
return;
|
|
298
326
|
}
|
|
299
|
-
const
|
|
327
|
+
const hasEmptyDeps = tools.F.pipe(
|
|
300
328
|
$(deps).with({ type: ast.NodeType.ArrayExpression }, tools.O.some).with({ type: ast.NodeType.Identifier }, (n2) => {
|
|
301
329
|
return tools.F.pipe(
|
|
302
330
|
_var.findVariable(n2.name, initialScope),
|
|
@@ -304,19 +332,194 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
304
332
|
tools.O.filter(ast.is(ast.NodeType.ArrayExpression))
|
|
305
333
|
);
|
|
306
334
|
}).otherwise(tools.O.none),
|
|
307
|
-
tools.O.
|
|
308
|
-
|
|
335
|
+
tools.O.exists((x2) => x2.elements.length === 0)
|
|
336
|
+
);
|
|
337
|
+
if (!hasEmptyDeps) return;
|
|
338
|
+
if (!cb) {
|
|
339
|
+
context.report({
|
|
309
340
|
messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
|
|
310
341
|
node
|
|
311
|
-
})
|
|
342
|
+
});
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const isReferencedToComponentScope = tools.F.pipe(
|
|
346
|
+
$(cb).with({ type: ast.NodeType.ArrowFunctionExpression }, tools.O.some).with({ type: ast.NodeType.FunctionExpression }, tools.O.some).with({ type: ast.NodeType.Identifier }, (n2) => {
|
|
347
|
+
return tools.F.pipe(
|
|
348
|
+
_var.findVariable(n2.name, initialScope),
|
|
349
|
+
tools.O.flatMap(_var.getVariableInit(0)),
|
|
350
|
+
tools.O.filter(ast.isFunction)
|
|
351
|
+
);
|
|
352
|
+
}).otherwise(tools.O.none),
|
|
353
|
+
tools.O.map((n2) => context.sourceCode.getScope(n2).references),
|
|
354
|
+
tools.O.exists((refs) => refs.some((x2) => x2.resolved?.scope.block === component))
|
|
355
|
+
);
|
|
356
|
+
if (isReferencedToComponentScope) return;
|
|
357
|
+
context.report({
|
|
358
|
+
messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
|
|
359
|
+
node
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
},
|
|
364
|
+
defaultOptions: []
|
|
365
|
+
});
|
|
366
|
+
var RULE_NAME4 = "no-direct-set-state-in-use-effect";
|
|
367
|
+
var no_direct_set_state_in_use_effect_default = createRule({
|
|
368
|
+
meta: {
|
|
369
|
+
type: "problem",
|
|
370
|
+
docs: {
|
|
371
|
+
description: "disallow direct calls to the 'set' function of 'useState' in 'useEffect'"
|
|
372
|
+
},
|
|
373
|
+
messages: {
|
|
374
|
+
NO_DIRECT_SET_STATE_IN_USE_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useEffect'."
|
|
375
|
+
},
|
|
376
|
+
schema: []
|
|
377
|
+
},
|
|
378
|
+
name: RULE_NAME4,
|
|
379
|
+
create(context) {
|
|
380
|
+
const settings = shared.getESLintReactSettings(context.settings);
|
|
381
|
+
const { useEffect: useEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
|
|
382
|
+
function isUseEffectCallWithAlias(node, context2) {
|
|
383
|
+
return core.isUseEffectCall(node, context2) || useEffectAlias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node));
|
|
384
|
+
}
|
|
385
|
+
function isUseStateCallWithAlias(node, context2) {
|
|
386
|
+
return core.isUseStateCall(node, context2) || useStateAlias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node));
|
|
387
|
+
}
|
|
388
|
+
function isEffectFunction(node) {
|
|
389
|
+
return node.parent?.type === ast.NodeType.CallExpression && isUseEffectCallWithAlias(node.parent, context);
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
CallExpression(node) {
|
|
393
|
+
const effectFunction = ast.traverseUp(node, isEffectFunction);
|
|
394
|
+
if (tools.O.isNone(effectFunction)) return;
|
|
395
|
+
const scope = context.sourceCode.getScope(node);
|
|
396
|
+
if (scope.block !== effectFunction.value) return;
|
|
397
|
+
const name2 = $(node.callee).with({ type: ast.NodeType.Identifier }, (n2) => tools.O.some(n2.name)).with({ type: ast.NodeType.MemberExpression }, (n2) => {
|
|
398
|
+
if (!("name" in n2.object)) return tools.O.none();
|
|
399
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
400
|
+
const property = astUtils.getStaticValue(n2.property, initialScope);
|
|
401
|
+
if (property?.value === 1) return tools.O.fromNullable(n2.object.name);
|
|
402
|
+
return tools.O.none();
|
|
403
|
+
}).with({ type: ast.NodeType.CallExpression }, (n2) => {
|
|
404
|
+
if (!ast.is(ast.NodeType.MemberExpression)(n2.callee)) return tools.O.none();
|
|
405
|
+
if (!("name" in n2.callee.object)) return tools.O.none();
|
|
406
|
+
const isAt = $(n2.callee).with(
|
|
407
|
+
{
|
|
408
|
+
type: ast.NodeType.MemberExpression,
|
|
409
|
+
property: {
|
|
410
|
+
type: ast.NodeType.Identifier,
|
|
411
|
+
name: "at"
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
tools.F.constTrue
|
|
415
|
+
).otherwise(tools.F.constFalse);
|
|
416
|
+
if (!isAt) return tools.O.none();
|
|
417
|
+
const [index] = n2.arguments;
|
|
418
|
+
if (!index) return tools.O.none();
|
|
419
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
420
|
+
const value = astUtils.getStaticValue(index, initialScope);
|
|
421
|
+
if (value?.value === 1) return tools.O.fromNullable(n2.callee.object.name);
|
|
422
|
+
return tools.O.none();
|
|
423
|
+
}).otherwise(tools.O.none);
|
|
424
|
+
tools.F.pipe(
|
|
425
|
+
name2,
|
|
426
|
+
tools.O.flatMap(_var.findVariable(scope)),
|
|
427
|
+
tools.O.flatMap(_var.getVariableInit(0)),
|
|
428
|
+
tools.O.filter(ast.is(ast.NodeType.CallExpression)),
|
|
429
|
+
tools.O.filter((name3) => isUseStateCallWithAlias(name3, context)),
|
|
430
|
+
tools.O.map((name3) => ({
|
|
431
|
+
data: {
|
|
432
|
+
setState: name3
|
|
433
|
+
},
|
|
434
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
|
|
435
|
+
node
|
|
436
|
+
})),
|
|
437
|
+
tools.O.map(context.report)
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
},
|
|
442
|
+
defaultOptions: []
|
|
443
|
+
});
|
|
444
|
+
var RULE_NAME5 = "no-direct-set-state-in-use-layout-effect";
|
|
445
|
+
var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
446
|
+
meta: {
|
|
447
|
+
type: "problem",
|
|
448
|
+
docs: {
|
|
449
|
+
description: "disallow direct calls to the 'set' function of 'useState' in 'useLayoutEffect'"
|
|
450
|
+
},
|
|
451
|
+
messages: {
|
|
452
|
+
NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useLayoutEffect'."
|
|
453
|
+
},
|
|
454
|
+
schema: []
|
|
455
|
+
},
|
|
456
|
+
name: RULE_NAME5,
|
|
457
|
+
create(context) {
|
|
458
|
+
const settings = shared.getESLintReactSettings(context.settings);
|
|
459
|
+
const { useLayoutEffect: useLayoutEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
|
|
460
|
+
function isUseLayoutEffectCallWithAlias(node, context2) {
|
|
461
|
+
return core.isUseLayoutEffectCall(node, context2) || useLayoutEffectAlias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node));
|
|
462
|
+
}
|
|
463
|
+
function isUseStateCallWithAlias(node, context2) {
|
|
464
|
+
return core.isUseStateCall(node, context2) || useStateAlias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node));
|
|
465
|
+
}
|
|
466
|
+
function isEffectFunction(node) {
|
|
467
|
+
return node.parent?.type === ast.NodeType.CallExpression && isUseLayoutEffectCallWithAlias(node.parent, context);
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
CallExpression(node) {
|
|
471
|
+
const effectFunction = ast.traverseUp(node, isEffectFunction);
|
|
472
|
+
if (tools.O.isNone(effectFunction)) return;
|
|
473
|
+
const scope = context.sourceCode.getScope(node);
|
|
474
|
+
if (scope.block !== effectFunction.value) return;
|
|
475
|
+
const name2 = $(node.callee).with({ type: ast.NodeType.Identifier }, (n2) => tools.O.some(n2.name)).with({ type: ast.NodeType.MemberExpression }, (n2) => {
|
|
476
|
+
if (!("name" in n2.object)) return tools.O.none();
|
|
477
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
478
|
+
const property = astUtils.getStaticValue(n2.property, initialScope);
|
|
479
|
+
if (property?.value === 1) return tools.O.fromNullable(n2.object.name);
|
|
480
|
+
return tools.O.none();
|
|
481
|
+
}).with({ type: ast.NodeType.CallExpression }, (n2) => {
|
|
482
|
+
if (!ast.is(ast.NodeType.MemberExpression)(n2.callee)) return tools.O.none();
|
|
483
|
+
if (!("name" in n2.callee.object)) return tools.O.none();
|
|
484
|
+
const isAt = $(n2.callee).with(
|
|
485
|
+
{
|
|
486
|
+
type: ast.NodeType.MemberExpression,
|
|
487
|
+
property: {
|
|
488
|
+
type: ast.NodeType.Identifier,
|
|
489
|
+
name: "at"
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
tools.F.constTrue
|
|
493
|
+
).otherwise(tools.F.constFalse);
|
|
494
|
+
if (!isAt) return tools.O.none();
|
|
495
|
+
const [index] = n2.arguments;
|
|
496
|
+
if (!index) return tools.O.none();
|
|
497
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
498
|
+
const value = astUtils.getStaticValue(index, initialScope);
|
|
499
|
+
if (value?.value === 1) return tools.O.fromNullable(n2.callee.object.name);
|
|
500
|
+
return tools.O.none();
|
|
501
|
+
}).otherwise(tools.O.none);
|
|
502
|
+
tools.F.pipe(
|
|
503
|
+
name2,
|
|
504
|
+
tools.O.flatMap(_var.findVariable(scope)),
|
|
505
|
+
tools.O.flatMap(_var.getVariableInit(0)),
|
|
506
|
+
tools.O.filter(ast.is(ast.NodeType.CallExpression)),
|
|
507
|
+
tools.O.filter((name3) => isUseStateCallWithAlias(name3, context)),
|
|
508
|
+
tools.O.map((name3) => ({
|
|
509
|
+
data: {
|
|
510
|
+
setState: name3
|
|
511
|
+
},
|
|
512
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
|
|
513
|
+
node
|
|
514
|
+
})),
|
|
515
|
+
tools.O.map(context.report)
|
|
312
516
|
);
|
|
313
|
-
tools.O.map(maybeDescriptor, context.report);
|
|
314
517
|
}
|
|
315
518
|
};
|
|
316
519
|
},
|
|
317
520
|
defaultOptions: []
|
|
318
521
|
});
|
|
319
|
-
var
|
|
522
|
+
var RULE_NAME6 = "prefer-use-state-lazy-initialization";
|
|
320
523
|
var ALLOW_LIST = ["Boolean", "String", "Number"];
|
|
321
524
|
var prefer_use_state_lazy_initialization_default = createRule({
|
|
322
525
|
meta: {
|
|
@@ -329,7 +532,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
|
|
|
329
532
|
},
|
|
330
533
|
schema: []
|
|
331
534
|
},
|
|
332
|
-
name:
|
|
535
|
+
name: RULE_NAME6,
|
|
333
536
|
create(context) {
|
|
334
537
|
const alias = shared.getESLintReactSettings(context.settings).additionalHooks?.useState ?? [];
|
|
335
538
|
return {
|
|
@@ -362,6 +565,8 @@ var rules = {
|
|
|
362
565
|
"ensure-custom-hooks-using-other-hooks": ensure_custom_hooks_using_other_hooks_default,
|
|
363
566
|
"ensure-use-callback-has-non-empty-deps": ensure_use_callback_has_non_empty_deps_default,
|
|
364
567
|
"ensure-use-memo-has-non-empty-deps": ensure_use_memo_has_non_empty_deps_default,
|
|
568
|
+
"no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
|
|
569
|
+
"no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_layout_effect_default,
|
|
365
570
|
"prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default
|
|
366
571
|
};
|
|
367
572
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { useHookCollector, isReactHookCall, isUseCallbackCall, isReactHookCallWithNameLoose, isUseMemoCall, isUseStateCall } from '@eslint-react/core';
|
|
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 { NodeType, is, getNestedCallExpressions } from '@eslint-react/ast';
|
|
3
|
+
import { isFunction, NodeType, is, traverseUp, getNestedCallExpressions } from '@eslint-react/ast';
|
|
4
4
|
import { F, O } from '@eslint-react/tools';
|
|
5
5
|
import { findVariable, getVariableInit } from '@eslint-react/var';
|
|
6
|
+
import { getStaticValue } from '@typescript-eslint/utils/ast-utils';
|
|
6
7
|
|
|
7
8
|
// package.json
|
|
8
9
|
var name = "eslint-plugin-react-hooks-extra";
|
|
9
|
-
var version = "1.5.
|
|
10
|
+
var version = "1.5.26-beta.2";
|
|
10
11
|
var createRule = createRuleForPlugin("hooks-extra");
|
|
11
12
|
|
|
12
13
|
// src/rules/ensure-custom-hooks-using-other-hooks.ts
|
|
@@ -224,7 +225,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
224
225
|
description: "enforce 'useCallback' has non-empty dependencies array"
|
|
225
226
|
},
|
|
226
227
|
messages: {
|
|
227
|
-
ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS: "An useCallback should have a non-empty dependencies array."
|
|
228
|
+
ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS: "An 'useCallback' should have a non-empty dependencies array."
|
|
228
229
|
},
|
|
229
230
|
schema: []
|
|
230
231
|
},
|
|
@@ -233,12 +234,15 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
233
234
|
const alias = getESLintReactSettings(context.settings).additionalHooks?.useCallback ?? [];
|
|
234
235
|
return {
|
|
235
236
|
CallExpression(node) {
|
|
236
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
237
237
|
if (!isReactHookCall(node)) return;
|
|
238
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
238
239
|
if (!isUseCallbackCall(node, context) && !alias.some(F.flip(isReactHookCallWithNameLoose)(node))) {
|
|
239
240
|
return;
|
|
240
241
|
}
|
|
241
|
-
const
|
|
242
|
+
const scope = context.sourceCode.getScope(node);
|
|
243
|
+
const component = scope.block;
|
|
244
|
+
if (!isFunction(component)) return;
|
|
245
|
+
const [cb, deps] = node.arguments;
|
|
242
246
|
if (!deps) {
|
|
243
247
|
context.report({
|
|
244
248
|
messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
|
|
@@ -246,7 +250,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
246
250
|
});
|
|
247
251
|
return;
|
|
248
252
|
}
|
|
249
|
-
const
|
|
253
|
+
const hasEmptyDeps = F.pipe(
|
|
250
254
|
$(deps).with({ type: NodeType.ArrayExpression }, O.some).with({ type: NodeType.Identifier }, (n2) => {
|
|
251
255
|
return F.pipe(
|
|
252
256
|
findVariable(n2.name, initialScope),
|
|
@@ -254,13 +258,32 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
|
|
|
254
258
|
O.filter(is(NodeType.ArrayExpression))
|
|
255
259
|
);
|
|
256
260
|
}).otherwise(O.none),
|
|
257
|
-
O.
|
|
258
|
-
|
|
261
|
+
O.exists((x2) => x2.elements.length === 0)
|
|
262
|
+
);
|
|
263
|
+
if (!hasEmptyDeps) return;
|
|
264
|
+
if (!cb) {
|
|
265
|
+
context.report({
|
|
259
266
|
messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
|
|
260
267
|
node
|
|
261
|
-
})
|
|
268
|
+
});
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const isReferencedToComponentScope = F.pipe(
|
|
272
|
+
$(cb).with({ type: NodeType.ArrowFunctionExpression }, O.some).with({ type: NodeType.FunctionExpression }, O.some).with({ type: NodeType.Identifier }, (n2) => {
|
|
273
|
+
return F.pipe(
|
|
274
|
+
findVariable(n2.name, initialScope),
|
|
275
|
+
O.flatMap(getVariableInit(0)),
|
|
276
|
+
O.filter(isFunction)
|
|
277
|
+
);
|
|
278
|
+
}).otherwise(O.none),
|
|
279
|
+
O.map((n2) => context.sourceCode.getScope(n2).references),
|
|
280
|
+
O.exists((refs) => refs.some((x2) => x2.resolved?.scope.block === component))
|
|
262
281
|
);
|
|
263
|
-
|
|
282
|
+
if (isReferencedToComponentScope) return;
|
|
283
|
+
context.report({
|
|
284
|
+
messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
|
|
285
|
+
node
|
|
286
|
+
});
|
|
264
287
|
}
|
|
265
288
|
};
|
|
266
289
|
},
|
|
@@ -274,7 +297,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
274
297
|
description: "enforce 'useMemo' has non-empty dependencies array"
|
|
275
298
|
},
|
|
276
299
|
messages: {
|
|
277
|
-
ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS: "An useMemo should have a non-empty dependencies array."
|
|
300
|
+
ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS: "An 'useMemo' should have a non-empty dependencies array."
|
|
278
301
|
},
|
|
279
302
|
schema: []
|
|
280
303
|
},
|
|
@@ -283,10 +306,15 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
283
306
|
const alias = getESLintReactSettings(context.settings).additionalHooks?.useMemo ?? [];
|
|
284
307
|
return {
|
|
285
308
|
CallExpression(node) {
|
|
286
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
287
309
|
if (!isReactHookCall(node)) return;
|
|
288
|
-
|
|
289
|
-
|
|
310
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
311
|
+
if (!isUseMemoCall(node, context) && !alias.some(F.flip(isReactHookCallWithNameLoose)(node))) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const scope = context.sourceCode.getScope(node);
|
|
315
|
+
const component = scope.block;
|
|
316
|
+
if (!isFunction(component)) return;
|
|
317
|
+
const [cb, deps] = node.arguments;
|
|
290
318
|
if (!deps) {
|
|
291
319
|
context.report({
|
|
292
320
|
messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
|
|
@@ -294,7 +322,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
294
322
|
});
|
|
295
323
|
return;
|
|
296
324
|
}
|
|
297
|
-
const
|
|
325
|
+
const hasEmptyDeps = F.pipe(
|
|
298
326
|
$(deps).with({ type: NodeType.ArrayExpression }, O.some).with({ type: NodeType.Identifier }, (n2) => {
|
|
299
327
|
return F.pipe(
|
|
300
328
|
findVariable(n2.name, initialScope),
|
|
@@ -302,19 +330,194 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
|
|
|
302
330
|
O.filter(is(NodeType.ArrayExpression))
|
|
303
331
|
);
|
|
304
332
|
}).otherwise(O.none),
|
|
305
|
-
O.
|
|
306
|
-
|
|
333
|
+
O.exists((x2) => x2.elements.length === 0)
|
|
334
|
+
);
|
|
335
|
+
if (!hasEmptyDeps) return;
|
|
336
|
+
if (!cb) {
|
|
337
|
+
context.report({
|
|
307
338
|
messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
|
|
308
339
|
node
|
|
309
|
-
})
|
|
340
|
+
});
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const isReferencedToComponentScope = F.pipe(
|
|
344
|
+
$(cb).with({ type: NodeType.ArrowFunctionExpression }, O.some).with({ type: NodeType.FunctionExpression }, O.some).with({ type: NodeType.Identifier }, (n2) => {
|
|
345
|
+
return F.pipe(
|
|
346
|
+
findVariable(n2.name, initialScope),
|
|
347
|
+
O.flatMap(getVariableInit(0)),
|
|
348
|
+
O.filter(isFunction)
|
|
349
|
+
);
|
|
350
|
+
}).otherwise(O.none),
|
|
351
|
+
O.map((n2) => context.sourceCode.getScope(n2).references),
|
|
352
|
+
O.exists((refs) => refs.some((x2) => x2.resolved?.scope.block === component))
|
|
353
|
+
);
|
|
354
|
+
if (isReferencedToComponentScope) return;
|
|
355
|
+
context.report({
|
|
356
|
+
messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
|
|
357
|
+
node
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
},
|
|
362
|
+
defaultOptions: []
|
|
363
|
+
});
|
|
364
|
+
var RULE_NAME4 = "no-direct-set-state-in-use-effect";
|
|
365
|
+
var no_direct_set_state_in_use_effect_default = createRule({
|
|
366
|
+
meta: {
|
|
367
|
+
type: "problem",
|
|
368
|
+
docs: {
|
|
369
|
+
description: "disallow direct calls to the 'set' function of 'useState' in 'useEffect'"
|
|
370
|
+
},
|
|
371
|
+
messages: {
|
|
372
|
+
NO_DIRECT_SET_STATE_IN_USE_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useEffect'."
|
|
373
|
+
},
|
|
374
|
+
schema: []
|
|
375
|
+
},
|
|
376
|
+
name: RULE_NAME4,
|
|
377
|
+
create(context) {
|
|
378
|
+
const settings = getESLintReactSettings(context.settings);
|
|
379
|
+
const { useEffect: useEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
|
|
380
|
+
function isUseEffectCallWithAlias(node, context2) {
|
|
381
|
+
return isUseEffectCall(node, context2) || useEffectAlias.some(F.flip(isReactHookCallWithNameLoose)(node));
|
|
382
|
+
}
|
|
383
|
+
function isUseStateCallWithAlias(node, context2) {
|
|
384
|
+
return isUseStateCall(node, context2) || useStateAlias.some(F.flip(isReactHookCallWithNameLoose)(node));
|
|
385
|
+
}
|
|
386
|
+
function isEffectFunction(node) {
|
|
387
|
+
return node.parent?.type === NodeType.CallExpression && isUseEffectCallWithAlias(node.parent, context);
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
CallExpression(node) {
|
|
391
|
+
const effectFunction = traverseUp(node, isEffectFunction);
|
|
392
|
+
if (O.isNone(effectFunction)) return;
|
|
393
|
+
const scope = context.sourceCode.getScope(node);
|
|
394
|
+
if (scope.block !== effectFunction.value) return;
|
|
395
|
+
const name2 = $(node.callee).with({ type: NodeType.Identifier }, (n2) => O.some(n2.name)).with({ type: NodeType.MemberExpression }, (n2) => {
|
|
396
|
+
if (!("name" in n2.object)) return O.none();
|
|
397
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
398
|
+
const property = getStaticValue(n2.property, initialScope);
|
|
399
|
+
if (property?.value === 1) return O.fromNullable(n2.object.name);
|
|
400
|
+
return O.none();
|
|
401
|
+
}).with({ type: NodeType.CallExpression }, (n2) => {
|
|
402
|
+
if (!is(NodeType.MemberExpression)(n2.callee)) return O.none();
|
|
403
|
+
if (!("name" in n2.callee.object)) return O.none();
|
|
404
|
+
const isAt = $(n2.callee).with(
|
|
405
|
+
{
|
|
406
|
+
type: NodeType.MemberExpression,
|
|
407
|
+
property: {
|
|
408
|
+
type: NodeType.Identifier,
|
|
409
|
+
name: "at"
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
F.constTrue
|
|
413
|
+
).otherwise(F.constFalse);
|
|
414
|
+
if (!isAt) return O.none();
|
|
415
|
+
const [index] = n2.arguments;
|
|
416
|
+
if (!index) return O.none();
|
|
417
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
418
|
+
const value = getStaticValue(index, initialScope);
|
|
419
|
+
if (value?.value === 1) return O.fromNullable(n2.callee.object.name);
|
|
420
|
+
return O.none();
|
|
421
|
+
}).otherwise(O.none);
|
|
422
|
+
F.pipe(
|
|
423
|
+
name2,
|
|
424
|
+
O.flatMap(findVariable(scope)),
|
|
425
|
+
O.flatMap(getVariableInit(0)),
|
|
426
|
+
O.filter(is(NodeType.CallExpression)),
|
|
427
|
+
O.filter((name3) => isUseStateCallWithAlias(name3, context)),
|
|
428
|
+
O.map((name3) => ({
|
|
429
|
+
data: {
|
|
430
|
+
setState: name3
|
|
431
|
+
},
|
|
432
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_EFFECT",
|
|
433
|
+
node
|
|
434
|
+
})),
|
|
435
|
+
O.map(context.report)
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
},
|
|
440
|
+
defaultOptions: []
|
|
441
|
+
});
|
|
442
|
+
var RULE_NAME5 = "no-direct-set-state-in-use-layout-effect";
|
|
443
|
+
var no_direct_set_state_in_use_layout_effect_default = createRule({
|
|
444
|
+
meta: {
|
|
445
|
+
type: "problem",
|
|
446
|
+
docs: {
|
|
447
|
+
description: "disallow direct calls to the 'set' function of 'useState' in 'useLayoutEffect'"
|
|
448
|
+
},
|
|
449
|
+
messages: {
|
|
450
|
+
NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT: "Do not call the 'set' function of 'useState' directly in 'useLayoutEffect'."
|
|
451
|
+
},
|
|
452
|
+
schema: []
|
|
453
|
+
},
|
|
454
|
+
name: RULE_NAME5,
|
|
455
|
+
create(context) {
|
|
456
|
+
const settings = getESLintReactSettings(context.settings);
|
|
457
|
+
const { useLayoutEffect: useLayoutEffectAlias = [], useState: useStateAlias = [] } = settings.additionalHooks ?? {};
|
|
458
|
+
function isUseLayoutEffectCallWithAlias(node, context2) {
|
|
459
|
+
return isUseLayoutEffectCall(node, context2) || useLayoutEffectAlias.some(F.flip(isReactHookCallWithNameLoose)(node));
|
|
460
|
+
}
|
|
461
|
+
function isUseStateCallWithAlias(node, context2) {
|
|
462
|
+
return isUseStateCall(node, context2) || useStateAlias.some(F.flip(isReactHookCallWithNameLoose)(node));
|
|
463
|
+
}
|
|
464
|
+
function isEffectFunction(node) {
|
|
465
|
+
return node.parent?.type === NodeType.CallExpression && isUseLayoutEffectCallWithAlias(node.parent, context);
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
CallExpression(node) {
|
|
469
|
+
const effectFunction = traverseUp(node, isEffectFunction);
|
|
470
|
+
if (O.isNone(effectFunction)) return;
|
|
471
|
+
const scope = context.sourceCode.getScope(node);
|
|
472
|
+
if (scope.block !== effectFunction.value) return;
|
|
473
|
+
const name2 = $(node.callee).with({ type: NodeType.Identifier }, (n2) => O.some(n2.name)).with({ type: NodeType.MemberExpression }, (n2) => {
|
|
474
|
+
if (!("name" in n2.object)) return O.none();
|
|
475
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
476
|
+
const property = getStaticValue(n2.property, initialScope);
|
|
477
|
+
if (property?.value === 1) return O.fromNullable(n2.object.name);
|
|
478
|
+
return O.none();
|
|
479
|
+
}).with({ type: NodeType.CallExpression }, (n2) => {
|
|
480
|
+
if (!is(NodeType.MemberExpression)(n2.callee)) return O.none();
|
|
481
|
+
if (!("name" in n2.callee.object)) return O.none();
|
|
482
|
+
const isAt = $(n2.callee).with(
|
|
483
|
+
{
|
|
484
|
+
type: NodeType.MemberExpression,
|
|
485
|
+
property: {
|
|
486
|
+
type: NodeType.Identifier,
|
|
487
|
+
name: "at"
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
F.constTrue
|
|
491
|
+
).otherwise(F.constFalse);
|
|
492
|
+
if (!isAt) return O.none();
|
|
493
|
+
const [index] = n2.arguments;
|
|
494
|
+
if (!index) return O.none();
|
|
495
|
+
const initialScope = context.sourceCode.getScope(n2);
|
|
496
|
+
const value = getStaticValue(index, initialScope);
|
|
497
|
+
if (value?.value === 1) return O.fromNullable(n2.callee.object.name);
|
|
498
|
+
return O.none();
|
|
499
|
+
}).otherwise(O.none);
|
|
500
|
+
F.pipe(
|
|
501
|
+
name2,
|
|
502
|
+
O.flatMap(findVariable(scope)),
|
|
503
|
+
O.flatMap(getVariableInit(0)),
|
|
504
|
+
O.filter(is(NodeType.CallExpression)),
|
|
505
|
+
O.filter((name3) => isUseStateCallWithAlias(name3, context)),
|
|
506
|
+
O.map((name3) => ({
|
|
507
|
+
data: {
|
|
508
|
+
setState: name3
|
|
509
|
+
},
|
|
510
|
+
messageId: "NO_DIRECT_SET_STATE_IN_USE_LAYOUT_EFFECT",
|
|
511
|
+
node
|
|
512
|
+
})),
|
|
513
|
+
O.map(context.report)
|
|
310
514
|
);
|
|
311
|
-
O.map(maybeDescriptor, context.report);
|
|
312
515
|
}
|
|
313
516
|
};
|
|
314
517
|
},
|
|
315
518
|
defaultOptions: []
|
|
316
519
|
});
|
|
317
|
-
var
|
|
520
|
+
var RULE_NAME6 = "prefer-use-state-lazy-initialization";
|
|
318
521
|
var ALLOW_LIST = ["Boolean", "String", "Number"];
|
|
319
522
|
var prefer_use_state_lazy_initialization_default = createRule({
|
|
320
523
|
meta: {
|
|
@@ -327,7 +530,7 @@ var prefer_use_state_lazy_initialization_default = createRule({
|
|
|
327
530
|
},
|
|
328
531
|
schema: []
|
|
329
532
|
},
|
|
330
|
-
name:
|
|
533
|
+
name: RULE_NAME6,
|
|
331
534
|
create(context) {
|
|
332
535
|
const alias = getESLintReactSettings(context.settings).additionalHooks?.useState ?? [];
|
|
333
536
|
return {
|
|
@@ -360,6 +563,8 @@ var rules = {
|
|
|
360
563
|
"ensure-custom-hooks-using-other-hooks": ensure_custom_hooks_using_other_hooks_default,
|
|
361
564
|
"ensure-use-callback-has-non-empty-deps": ensure_use_callback_has_non_empty_deps_default,
|
|
362
565
|
"ensure-use-memo-has-non-empty-deps": ensure_use_memo_has_non_empty_deps_default,
|
|
566
|
+
"no-direct-set-state-in-use-effect": no_direct_set_state_in_use_effect_default,
|
|
567
|
+
"no-direct-set-state-in-use-layout-effect": no_direct_set_state_in_use_layout_effect_default,
|
|
363
568
|
"prefer-use-state-lazy-initialization": prefer_use_state_lazy_initialization_default
|
|
364
569
|
};
|
|
365
570
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-hooks-extra",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.26-beta.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.0",
|
|
40
40
|
"@typescript-eslint/types": "^7.16.0",
|
|
41
41
|
"@typescript-eslint/utils": "^7.16.0",
|
|
42
|
-
"@eslint-react/
|
|
43
|
-
"@eslint-react/
|
|
44
|
-
"@eslint-react/
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/var": "1.5.
|
|
42
|
+
"@eslint-react/ast": "1.5.26-beta.2",
|
|
43
|
+
"@eslint-react/jsx": "1.5.26-beta.2",
|
|
44
|
+
"@eslint-react/core": "1.5.26-beta.2",
|
|
45
|
+
"@eslint-react/shared": "1.5.26-beta.2",
|
|
46
|
+
"@eslint-react/tools": "1.5.26-beta.2",
|
|
47
|
+
"@eslint-react/types": "1.5.26-beta.2",
|
|
48
|
+
"@eslint-react/var": "1.5.26-beta.2"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"string-ts": "2.2.0",
|