eslint-plugin-react-hooks-extra 1.23.3-next.8 → 1.24.0-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.
Files changed (3) hide show
  1. package/dist/index.js +144 -146
  2. package/dist/index.mjs +144 -146
  3. package/package.json +13 -13
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var AST2 = require('@eslint-react/ast');
3
+ var AST = require('@eslint-react/ast');
4
4
  var core = require('@eslint-react/core');
5
5
  var eff = require('@eslint-react/eff');
6
6
  var shared = require('@eslint-react/shared');
@@ -26,22 +26,23 @@ function _interopNamespace(e) {
26
26
  return Object.freeze(n);
27
27
  }
28
28
 
29
- var AST2__namespace = /*#__PURE__*/_interopNamespace(AST2);
29
+ var AST__namespace = /*#__PURE__*/_interopNamespace(AST);
30
30
  var VAR5__namespace = /*#__PURE__*/_interopNamespace(VAR5);
31
31
 
32
32
  // package.json
33
33
  var name = "eslint-plugin-react-hooks-extra";
34
- var version = "1.23.3-next.8";
34
+ var version = "1.24.0-beta.1";
35
35
  var createRule = shared.createRuleForPlugin("hooks-extra");
36
- function isFromHookCall(name2, context, settings, predicate = eff.F.constTrue) {
36
+ function isFromHookCall(name2, context, settings, predicate = eff.returnTrue) {
37
37
  const hookAlias = settings.additionalHooks?.[name2] ?? [];
38
- return (topLevelId) => eff.F.pipe(
39
- VAR5__namespace.findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
40
- eff.O.flatMap(VAR5__namespace.getVariableNode(0)),
41
- eff.O.filter(AST2__namespace.is(types.AST_NODE_TYPES.CallExpression)),
42
- eff.O.filter(core.isReactHookCallWithNameAlias(name2, context, hookAlias)),
43
- eff.O.exists((call) => predicate(topLevelId, call))
44
- );
38
+ return (topLevelId) => {
39
+ const variable = VAR5__namespace.findVariable(topLevelId, context.sourceCode.getScope(topLevelId));
40
+ const variableNode = VAR5__namespace.getVariableNode(variable, 0);
41
+ if (variableNode == null) return false;
42
+ if (variableNode.type !== types.AST_NODE_TYPES.CallExpression) return false;
43
+ if (!core.isReactHookCallWithNameAlias(name2, context, hookAlias)(variableNode)) return false;
44
+ return predicate(topLevelId, variableNode);
45
+ };
45
46
  }
46
47
  function isFromUseStateCall(context, settings) {
47
48
  const predicate = (topLevelId, call) => {
@@ -72,8 +73,13 @@ function isSetFunctionCall(context, settings) {
72
73
  if (!isAt || index == null) {
73
74
  return false;
74
75
  }
75
- const initialScope = context.sourceCode.getScope(node);
76
- return eff.O.exists(VAR5__namespace.getStaticValue(index, initialScope), (v) => v === 1) && isIdFromUseStateCall(callee.object);
76
+ const indexScope = context.sourceCode.getScope(node);
77
+ const indexValue = VAR5__namespace.toResolved({
78
+ kind: "lazy",
79
+ node: index,
80
+ initialScope: indexScope
81
+ }).value;
82
+ return indexValue === 1 && isIdFromUseStateCall(callee.object);
77
83
  }
78
84
  // const [data, setData] = useState();
79
85
  // setData();
@@ -86,8 +92,14 @@ function isSetFunctionCall(context, settings) {
86
92
  if (!("name" in node.callee.object)) {
87
93
  return false;
88
94
  }
89
- const initialScope = context.sourceCode.getScope(node);
90
- return eff.O.exists(VAR5__namespace.getStaticValue(node.callee.property, initialScope), (v) => v === 1) && isIdFromUseStateCall(node.callee.object);
95
+ const property = node.callee.property;
96
+ const propertyScope = context.sourceCode.getScope(node);
97
+ const propertyValue = VAR5__namespace.toResolved({
98
+ kind: "lazy",
99
+ node: property,
100
+ initialScope: propertyScope
101
+ }).value;
102
+ return propertyValue === 1 && isIdFromUseStateCall(node.callee.object);
91
103
  }
92
104
  default: {
93
105
  return false;
@@ -148,8 +160,8 @@ var no_direct_set_state_in_use_effect_default = createRule({
148
160
  const isUseCallbackCall2 = core.isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
149
161
  const isSetStateCall = isSetFunctionCall(context, settings);
150
162
  const isIdFromUseStateCall = isFromUseStateCall(context, settings);
151
- const functionStack = [];
152
- const setupFunctionRef = { current: eff.O.none() };
163
+ const functionEntries = [];
164
+ const setupFunctionRef = { current: null };
153
165
  const setupFunctionIdentifiers = [];
154
166
  const indFunctionCalls = [];
155
167
  const indSetStateCalls = /* @__PURE__ */ new WeakMap();
@@ -157,10 +169,12 @@ var no_direct_set_state_in_use_effect_default = createRule({
157
169
  const indSetStateCallsInUseEffectSetup = /* @__PURE__ */ new Map();
158
170
  const indSetStateCallsInUseMemoOrCallback = /* @__PURE__ */ new WeakMap();
159
171
  const onSetupFunctionEnter = (node) => {
160
- setupFunctionRef.current = eff.O.some(node);
172
+ setupFunctionRef.current = node;
161
173
  };
162
174
  const onSetupFunctionExit = (node) => {
163
- setupFunctionRef.current = eff.O.filter(setupFunctionRef.current, (current) => current !== node);
175
+ if (setupFunctionRef.current === node) {
176
+ setupFunctionRef.current = null;
177
+ }
164
178
  };
165
179
  function isSetupFunction(node) {
166
180
  return node.parent?.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectLikeCall(node.parent);
@@ -169,33 +183,30 @@ var no_direct_set_state_in_use_effect_default = createRule({
169
183
  return tsPattern.match(node).when(isUseStateCall2, () => "useState").when(isUseEffectLikeCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
170
184
  }
171
185
  function getFunctionKind(node) {
172
- return tsPattern.match(node).when(isSetupFunction, () => "setup").when(AST2__namespace.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
186
+ return tsPattern.match(node).when(isSetupFunction, () => "setup").when(AST__namespace.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
173
187
  }
174
188
  return {
175
189
  ":function"(node) {
176
190
  const kind = getFunctionKind(node);
177
- functionStack.push({ kind, node });
191
+ functionEntries.push({ kind, node });
178
192
  if (kind === "setup") {
179
193
  onSetupFunctionEnter(node);
180
194
  }
181
195
  },
182
196
  ":function:exit"(node) {
183
- const { kind } = functionStack.at(-1) ?? {};
197
+ const { kind } = functionEntries.at(-1) ?? {};
184
198
  if (kind === "setup") {
185
199
  onSetupFunctionExit(node);
186
200
  }
187
- functionStack.pop();
201
+ functionEntries.pop();
188
202
  },
189
203
  CallExpression(node) {
190
- const setupFunction = eff.O.getOrNull(setupFunctionRef.current);
191
- const pEntry = functionStack.at(-1);
192
- if (pEntry?.node.async) {
204
+ const setupFunction = setupFunctionRef.current;
205
+ const pEntry = functionEntries.at(-1);
206
+ if (pEntry == null || pEntry.node.async) {
193
207
  return;
194
208
  }
195
209
  tsPattern.match(getCallKind(node)).with("setState", () => {
196
- if (pEntry == null) {
197
- return;
198
- }
199
210
  switch (true) {
200
211
  case (pEntry.node === setupFunction || pEntry.kind === "immediate"): {
201
212
  context.report({
@@ -208,28 +219,28 @@ var no_direct_set_state_in_use_effect_default = createRule({
208
219
  return;
209
220
  }
210
221
  default: {
211
- const mbVariableDeclarator = AST2__namespace.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
212
- if (eff.O.isNone(mbVariableDeclarator)) {
222
+ const variableDeclarator = AST__namespace.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
223
+ if (variableDeclarator == null) {
213
224
  const calls = indSetStateCalls.get(pEntry.node) ?? [];
214
225
  indSetStateCalls.set(pEntry.node, [...calls, node]);
215
226
  return;
216
227
  }
217
- const vd = mbVariableDeclarator.value;
218
- const prevs = indSetStateCallsInUseMemoOrCallback.get(vd.init) ?? [];
219
- indSetStateCallsInUseMemoOrCallback.set(vd.init, [...prevs, node]);
228
+ const init = variableDeclarator.init;
229
+ const prevs = indSetStateCallsInUseMemoOrCallback.get(init) ?? [];
230
+ indSetStateCallsInUseMemoOrCallback.set(init, [...prevs, node]);
220
231
  }
221
232
  }
222
233
  }).with("useEffect", () => {
223
- if (AST2__namespace.isFunction(node.arguments.at(0))) {
234
+ if (AST__namespace.isFunction(node.arguments.at(0))) {
224
235
  return;
225
236
  }
226
- setupFunctionIdentifiers.push(...AST2__namespace.getNestedIdentifiers(node));
237
+ setupFunctionIdentifiers.push(...AST__namespace.getNestedIdentifiers(node));
227
238
  }).with("other", () => {
228
- if (pEntry?.node !== setupFunction) {
239
+ if (pEntry.node !== setupFunction) {
229
240
  return;
230
241
  }
231
242
  indFunctionCalls.push(node);
232
- }).otherwise(eff.F.constVoid);
243
+ }).otherwise(() => eff._);
233
244
  },
234
245
  Identifier(node) {
235
246
  if (node.parent.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee === node) {
@@ -247,11 +258,10 @@ var no_direct_set_state_in_use_effect_default = createRule({
247
258
  if (!isUseMemoCall2(parent)) {
248
259
  break;
249
260
  }
250
- const mbVariableDeclarator = AST2__namespace.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
251
- if (eff.O.isNone(mbVariableDeclarator)) {
261
+ const variableDeclarator = AST__namespace.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
262
+ if (variableDeclarator == null) {
252
263
  break;
253
264
  }
254
- const variableDeclarator = mbVariableDeclarator.value;
255
265
  const calls = indSetStateCallsInUseEffectArg0.get(variableDeclarator.init) ?? [];
256
266
  indSetStateCallsInUseEffectArg0.set(variableDeclarator.init, [...calls, node]);
257
267
  break;
@@ -261,11 +271,10 @@ var no_direct_set_state_in_use_effect_default = createRule({
261
271
  break;
262
272
  }
263
273
  if (isUseCallbackCall2(node.parent)) {
264
- const mbVariableDeclarator = AST2__namespace.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
265
- if (eff.O.isNone(mbVariableDeclarator)) {
274
+ const variableDeclarator = AST__namespace.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
275
+ if (variableDeclarator == null) {
266
276
  break;
267
277
  }
268
- const variableDeclarator = mbVariableDeclarator.value;
269
278
  const prevs = indSetStateCallsInUseEffectArg0.get(variableDeclarator.init) ?? [];
270
279
  indSetStateCallsInUseEffectArg0.set(variableDeclarator.init, [...prevs, node]);
271
280
  }
@@ -279,7 +288,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
279
288
  },
280
289
  "Program:exit"() {
281
290
  const getSetStateCalls = (id, initialScope) => {
282
- const node = eff.O.flatMap(VAR5__namespace.findVariable(id, initialScope), VAR5__namespace.getVariableNode(0)).pipe(eff.O.getOrNull);
291
+ const node = VAR5__namespace.getVariableNode(VAR5__namespace.findVariable(id, initialScope), 0);
283
292
  switch (node?.type) {
284
293
  case types.AST_NODE_TYPES.ArrowFunctionExpression:
285
294
  case types.AST_NODE_TYPES.FunctionDeclaration:
@@ -290,7 +299,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
290
299
  }
291
300
  return [];
292
301
  };
293
- for (const [_, calls] of indSetStateCallsInUseEffectSetup) {
302
+ for (const [, calls] of indSetStateCallsInUseEffectSetup) {
294
303
  for (const call of calls) {
295
304
  context.report({
296
305
  messageId: "noDirectSetStateInUseEffect",
@@ -310,7 +319,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
310
319
  messageId: "noDirectSetStateInUseEffect",
311
320
  node: setStateCall,
312
321
  data: {
313
- name: AST2__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
322
+ name: AST__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
314
323
  }
315
324
  });
316
325
  }
@@ -322,7 +331,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
322
331
  messageId: "noDirectSetStateInUseEffect",
323
332
  node: setStateCall,
324
333
  data: {
325
- name: AST2__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
334
+ name: AST__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
326
335
  }
327
336
  });
328
337
  }
@@ -365,8 +374,8 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
365
374
  const isUseCallbackCall2 = core.isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
366
375
  const isSetStateCall = isSetFunctionCall(context, settings);
367
376
  const isIdFromUseStateCall = isFromUseStateCall(context, settings);
368
- const functionStack = [];
369
- const setupFunctionRef = { current: eff.O.none() };
377
+ const functionEntries = [];
378
+ const setupFunctionRef = { current: null };
370
379
  const setupFunctionIdentifiers = [];
371
380
  const indFunctionCalls = [];
372
381
  const indSetStateCalls = /* @__PURE__ */ new WeakMap();
@@ -374,10 +383,12 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
374
383
  const indSetStateCallsInUseLayoutEffectSetup = /* @__PURE__ */ new Map();
375
384
  const indSetStateCallsInUseMemoOrCallback = /* @__PURE__ */ new WeakMap();
376
385
  const onSetupFunctionEnter = (node) => {
377
- setupFunctionRef.current = eff.O.some(node);
386
+ setupFunctionRef.current = node;
378
387
  };
379
388
  const onSetupFunctionExit = (node) => {
380
- setupFunctionRef.current = eff.O.filter(setupFunctionRef.current, (current) => current !== node);
389
+ if (setupFunctionRef.current === node) {
390
+ setupFunctionRef.current = null;
391
+ }
381
392
  };
382
393
  function isSetupFunction(node) {
383
394
  return node.parent?.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseLayoutEffectLikeCall(node.parent);
@@ -386,33 +397,30 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
386
397
  return tsPattern.match(node).when(isUseStateCall2, () => "useState").when(isUseLayoutEffectLikeCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
387
398
  }
388
399
  function getFunctionKind(node) {
389
- return tsPattern.match(node).when(isSetupFunction, () => "setup").when(AST2__namespace.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
400
+ return tsPattern.match(node).when(isSetupFunction, () => "setup").when(AST__namespace.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
390
401
  }
391
402
  return {
392
403
  ":function"(node) {
393
404
  const kind = getFunctionKind(node);
394
- functionStack.push({ kind, node });
405
+ functionEntries.push({ kind, node });
395
406
  if (kind === "setup") {
396
407
  onSetupFunctionEnter(node);
397
408
  }
398
409
  },
399
410
  ":function:exit"(node) {
400
- const { kind } = functionStack.at(-1) ?? {};
411
+ const { kind } = functionEntries.at(-1) ?? {};
401
412
  if (kind === "setup") {
402
413
  onSetupFunctionExit(node);
403
414
  }
404
- functionStack.pop();
415
+ functionEntries.pop();
405
416
  },
406
417
  CallExpression(node) {
407
- const setupFunction = eff.O.getOrNull(setupFunctionRef.current);
408
- const pEntry = functionStack.at(-1);
409
- if (pEntry?.node.async) {
418
+ const setupFunction = setupFunctionRef.current;
419
+ const pEntry = functionEntries.at(-1);
420
+ if (pEntry == null || pEntry.node.async) {
410
421
  return;
411
422
  }
412
423
  tsPattern.match(getCallKind(node)).with("setState", () => {
413
- if (pEntry == null) {
414
- return;
415
- }
416
424
  switch (true) {
417
425
  case (pEntry.node === setupFunction || pEntry.kind === "immediate"): {
418
426
  context.report({
@@ -425,28 +433,28 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
425
433
  return;
426
434
  }
427
435
  default: {
428
- const mbVariableDeclarator = AST2__namespace.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
429
- if (eff.O.isNone(mbVariableDeclarator)) {
436
+ const variableDeclarator = AST__namespace.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
437
+ if (variableDeclarator == null) {
430
438
  const calls = indSetStateCalls.get(pEntry.node) ?? [];
431
439
  indSetStateCalls.set(pEntry.node, [...calls, node]);
432
440
  return;
433
441
  }
434
- const vd = mbVariableDeclarator.value;
435
- const prevs = indSetStateCallsInUseMemoOrCallback.get(vd.init) ?? [];
436
- indSetStateCallsInUseMemoOrCallback.set(vd.init, [...prevs, node]);
442
+ const init = variableDeclarator.init;
443
+ const prevs = indSetStateCallsInUseMemoOrCallback.get(init) ?? [];
444
+ indSetStateCallsInUseMemoOrCallback.set(init, [...prevs, node]);
437
445
  }
438
446
  }
439
447
  }).with("useLayoutEffect", () => {
440
- if (AST2__namespace.isFunction(node.arguments.at(0))) {
448
+ if (AST__namespace.isFunction(node.arguments.at(0))) {
441
449
  return;
442
450
  }
443
- setupFunctionIdentifiers.push(...AST2__namespace.getNestedIdentifiers(node));
451
+ setupFunctionIdentifiers.push(...AST__namespace.getNestedIdentifiers(node));
444
452
  }).with("other", () => {
445
- if (pEntry?.node !== setupFunction) {
453
+ if (pEntry.node !== setupFunction) {
446
454
  return;
447
455
  }
448
456
  indFunctionCalls.push(node);
449
- }).otherwise(eff.F.constVoid);
457
+ }).otherwise(() => eff._);
450
458
  },
451
459
  Identifier(node) {
452
460
  if (node.parent.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee === node) {
@@ -464,11 +472,10 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
464
472
  if (!isUseMemoCall2(parent)) {
465
473
  break;
466
474
  }
467
- const mbVariableDeclarator = AST2__namespace.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
468
- if (eff.O.isNone(mbVariableDeclarator)) {
475
+ const variableDeclarator = AST__namespace.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
476
+ if (variableDeclarator == null) {
469
477
  break;
470
478
  }
471
- const variableDeclarator = mbVariableDeclarator.value;
472
479
  const calls = indSetStateCallsInUseLayoutEffectArg0.get(variableDeclarator.init) ?? [];
473
480
  indSetStateCallsInUseLayoutEffectArg0.set(variableDeclarator.init, [...calls, node]);
474
481
  break;
@@ -478,11 +485,10 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
478
485
  break;
479
486
  }
480
487
  if (isUseCallbackCall2(node.parent)) {
481
- const mbVariableDeclarator = AST2__namespace.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
482
- if (eff.O.isNone(mbVariableDeclarator)) {
488
+ const variableDeclarator = AST__namespace.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
489
+ if (variableDeclarator == null) {
483
490
  break;
484
491
  }
485
- const variableDeclarator = mbVariableDeclarator.value;
486
492
  const prevs = indSetStateCallsInUseLayoutEffectArg0.get(variableDeclarator.init) ?? [];
487
493
  indSetStateCallsInUseLayoutEffectArg0.set(variableDeclarator.init, [...prevs, node]);
488
494
  }
@@ -496,7 +502,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
496
502
  },
497
503
  "Program:exit"() {
498
504
  const getSetStateCalls = (id, initialScope) => {
499
- const node = eff.O.flatMap(VAR5__namespace.findVariable(id, initialScope), VAR5__namespace.getVariableNode(0)).pipe(eff.O.getOrNull);
505
+ const node = VAR5__namespace.getVariableNode(VAR5__namespace.findVariable(id, initialScope), 0);
500
506
  switch (node?.type) {
501
507
  case types.AST_NODE_TYPES.ArrowFunctionExpression:
502
508
  case types.AST_NODE_TYPES.FunctionDeclaration:
@@ -507,7 +513,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
507
513
  }
508
514
  return [];
509
515
  };
510
- for (const [_, calls] of indSetStateCallsInUseLayoutEffectSetup) {
516
+ for (const [, calls] of indSetStateCallsInUseLayoutEffectSetup) {
511
517
  for (const call of calls) {
512
518
  context.report({
513
519
  messageId: "noDirectSetStateInUseLayoutEffect",
@@ -527,7 +533,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
527
533
  messageId: "noDirectSetStateInUseLayoutEffect",
528
534
  node: setStateCall,
529
535
  data: {
530
- name: AST2__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
536
+ name: AST__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
531
537
  }
532
538
  });
533
539
  }
@@ -539,7 +545,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
539
545
  messageId: "noDirectSetStateInUseLayoutEffect",
540
546
  node: setStateCall,
541
547
  data: {
542
- name: AST2__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
548
+ name: AST__namespace.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
543
549
  }
544
550
  });
545
551
  }
@@ -582,43 +588,41 @@ var no_unnecessary_use_callback_default = createRule({
582
588
  }
583
589
  const scope = context.sourceCode.getScope(node);
584
590
  const component = scope.block;
585
- if (!AST2__namespace.isFunction(component)) {
591
+ if (!AST__namespace.isFunction(component)) {
586
592
  return;
587
593
  }
588
594
  const [arg0, arg1] = node.arguments;
589
595
  if (arg0 == null || arg1 == null) {
590
596
  return;
591
597
  }
592
- const hasEmptyDeps = eff.F.pipe(
593
- tsPattern.match(arg1).with({ type: types.AST_NODE_TYPES.ArrayExpression }, eff.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
594
- return eff.F.pipe(
595
- VAR5__namespace.findVariable(n.name, initialScope),
596
- eff.O.flatMap(VAR5__namespace.getVariableNode(0)),
597
- eff.O.filter(AST2__namespace.is(types.AST_NODE_TYPES.ArrayExpression))
598
- );
599
- }).otherwise(eff.O.none),
600
- eff.O.exists((x) => x.elements.length === 0)
601
- );
598
+ const hasEmptyDeps = tsPattern.match(arg1).with({ type: types.AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
599
+ const variable = VAR5__namespace.findVariable(n.name, initialScope);
600
+ const variableNode = VAR5__namespace.getVariableNode(variable, 0);
601
+ if (variableNode?.type !== types.AST_NODE_TYPES.ArrayExpression) {
602
+ return false;
603
+ }
604
+ return variableNode.elements.length === 0;
605
+ }).otherwise(() => false);
602
606
  if (!hasEmptyDeps) {
603
607
  return;
604
608
  }
605
- const isReferencedToComponentScope = eff.F.pipe(
606
- tsPattern.match(arg0).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
607
- if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
608
- return eff.O.some(n.body);
609
- }
610
- return eff.O.some(n);
611
- }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, eff.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
612
- return eff.F.pipe(
613
- VAR5__namespace.findVariable(n.name, initialScope),
614
- eff.O.flatMap(VAR5__namespace.getVariableNode(0)),
615
- eff.O.filter(AST2__namespace.isFunction)
616
- );
617
- }).otherwise(eff.O.none),
618
- eff.O.map((n) => context.sourceCode.getScope(n)),
619
- eff.O.map((s) => VAR5__namespace.getChidScopes(s).flatMap((x) => x.references)),
620
- eff.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
621
- );
609
+ const arg0Node = tsPattern.match(arg0).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
610
+ if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
611
+ return n.body;
612
+ }
613
+ return n;
614
+ }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, eff.identity).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
615
+ const variable = VAR5__namespace.findVariable(n.name, initialScope);
616
+ const variableNode = VAR5__namespace.getVariableNode(variable, 0);
617
+ if (variableNode?.type !== types.AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== types.AST_NODE_TYPES.FunctionExpression) {
618
+ return eff._;
619
+ }
620
+ return variableNode;
621
+ }).otherwise(() => eff._);
622
+ if (arg0Node == null) return;
623
+ const arg0NodeScope = context.sourceCode.getScope(arg0Node);
624
+ const arg0NodeReferences = VAR5__namespace.getChidScopes(arg0NodeScope).flatMap((x) => x.references);
625
+ const isReferencedToComponentScope = arg0NodeReferences.some((x) => x.resolved?.scope.block === component);
622
626
  if (!isReferencedToComponentScope) {
623
627
  context.report({
624
628
  messageId: "noUnnecessaryUseCallback",
@@ -663,51 +667,45 @@ var no_unnecessary_use_memo_default = createRule({
663
667
  }
664
668
  const scope = context.sourceCode.getScope(node);
665
669
  const component = scope.block;
666
- if (!AST2__namespace.isFunction(component)) {
670
+ if (!AST__namespace.isFunction(component)) {
667
671
  return;
668
672
  }
669
673
  const [arg0, arg1] = node.arguments;
670
674
  if (arg0 == null || arg1 == null) {
671
675
  return;
672
676
  }
673
- const hasCallInArg0 = eff.F.pipe(
674
- eff.O.some(arg0),
675
- eff.O.filter((n) => AST2__namespace.isFunction(n)),
676
- eff.O.exists((n) => [...AST2__namespace.getNestedCallExpressions(n.body), ...AST2__namespace.getNestedNewExpressions(n.body)].length > 0)
677
- );
677
+ const hasCallInArg0 = AST__namespace.isFunction(arg0) && [...AST__namespace.getNestedCallExpressions(arg0.body), ...AST__namespace.getNestedNewExpressions(arg0.body)].length > 0;
678
678
  if (hasCallInArg0) {
679
679
  return;
680
680
  }
681
- const hasEmptyDeps = eff.F.pipe(
682
- tsPattern.match(arg1).with({ type: types.AST_NODE_TYPES.ArrayExpression }, eff.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
683
- return eff.F.pipe(
684
- VAR5__namespace.findVariable(n.name, initialScope),
685
- eff.O.flatMap(VAR5__namespace.getVariableNode(0)),
686
- eff.O.filter(AST2__namespace.is(types.AST_NODE_TYPES.ArrayExpression))
687
- );
688
- }).otherwise(eff.O.none),
689
- eff.O.exists((x) => x.elements.length === 0)
690
- );
681
+ const hasEmptyDeps = tsPattern.match(arg1).with({ type: types.AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
682
+ const variable = VAR5__namespace.findVariable(n.name, initialScope);
683
+ const variableNode = VAR5__namespace.getVariableNode(variable, 0);
684
+ if (variableNode?.type !== types.AST_NODE_TYPES.ArrayExpression) {
685
+ return false;
686
+ }
687
+ return variableNode.elements.length === 0;
688
+ }).otherwise(() => false);
691
689
  if (!hasEmptyDeps) {
692
690
  return;
693
691
  }
694
- const isReferencedToComponentScope = eff.F.pipe(
695
- tsPattern.match(arg0).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
696
- if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
697
- return eff.O.some(n.body);
698
- }
699
- return eff.O.some(n);
700
- }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, eff.O.some).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
701
- return eff.F.pipe(
702
- VAR5__namespace.findVariable(n.name, initialScope),
703
- eff.O.flatMap(VAR5__namespace.getVariableNode(0)),
704
- eff.O.filter(AST2__namespace.isFunction)
705
- );
706
- }).otherwise(eff.O.none),
707
- eff.O.map((n) => context.sourceCode.getScope(n)),
708
- eff.O.map((s) => VAR5__namespace.getChidScopes(s).flatMap((x) => x.references)),
709
- eff.O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
710
- );
692
+ const arg0Node = tsPattern.match(arg0).with({ type: types.AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
693
+ if (n.body.type === types.AST_NODE_TYPES.ArrowFunctionExpression) {
694
+ return n.body;
695
+ }
696
+ return n;
697
+ }).with({ type: types.AST_NODE_TYPES.FunctionExpression }, eff.identity).with({ type: types.AST_NODE_TYPES.Identifier }, (n) => {
698
+ const variable = VAR5__namespace.findVariable(n.name, initialScope);
699
+ const variableNode = VAR5__namespace.getVariableNode(variable, 0);
700
+ if (variableNode?.type !== types.AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== types.AST_NODE_TYPES.FunctionExpression) {
701
+ return eff._;
702
+ }
703
+ return variableNode;
704
+ }).otherwise(() => eff._);
705
+ if (arg0Node == null) return;
706
+ const arg0NodeScope = context.sourceCode.getScope(arg0Node);
707
+ const arg0NodeReferences = VAR5__namespace.getChidScopes(arg0NodeScope).flatMap((x) => x.references);
708
+ const isReferencedToComponentScope = arg0NodeReferences.some((x) => x.resolved?.scope.block === component);
711
709
  if (!isReferencedToComponentScope) {
712
710
  context.report({
713
711
  messageId: "noUnnecessaryUseMemo",
@@ -746,7 +744,7 @@ var no_useless_custom_hooks_default = createRule({
746
744
  "Program:exit"(node) {
747
745
  const allHooks = ctx.getAllHooks(node);
748
746
  for (const { name: name2, node: node2, hookCalls } of allHooks.values()) {
749
- if (AST2__namespace.isEmptyFunction(node2)) {
747
+ if (AST__namespace.isEmptyFunction(node2)) {
750
748
  continue;
751
749
  }
752
750
  if (hookCalls.length > 0) {
@@ -759,7 +757,7 @@ var no_useless_custom_hooks_default = createRule({
759
757
  messageId: "noUselessCustomHooks",
760
758
  node: node2,
761
759
  data: {
762
- name: name2.value
760
+ name: name2
763
761
  }
764
762
  });
765
763
  }
@@ -803,11 +801,11 @@ var prefer_use_state_lazy_initialization_default = createRule({
803
801
  if (useStateInput == null) {
804
802
  return;
805
803
  }
806
- const nestedCallExpressions = AST2__namespace.getNestedCallExpressions(useStateInput);
804
+ const nestedCallExpressions = AST__namespace.getNestedCallExpressions(useStateInput);
807
805
  const hasFunctionCall = nestedCallExpressions.some((n) => {
808
806
  return "name" in n.callee && !ALLOW_LIST.includes(n.callee.name);
809
807
  });
810
- const hasNewCall = AST2__namespace.getNestedNewExpressions(useStateInput).some((n) => {
808
+ const hasNewCall = AST__namespace.getNestedNewExpressions(useStateInput).some((n) => {
811
809
  return "name" in n.callee && !ALLOW_LIST.includes(n.callee.name);
812
810
  });
813
811
  if (!hasFunctionCall && !hasNewCall) {
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import * as AST2 from '@eslint-react/ast';
1
+ import * as AST from '@eslint-react/ast';
2
2
  import { isReactHookCallWithNameAlias, isReactHookCall, isUseCallbackCall, isReactHookCallWithNameLoose, isUseMemoCall, useHookCollector, isUseStateCall, isReactHookName } from '@eslint-react/core';
3
- import { O, F } from '@eslint-react/eff';
3
+ import { _, identity, returnTrue } from '@eslint-react/eff';
4
4
  import { createRuleForPlugin, getSettingsFromContext } from '@eslint-react/shared';
5
5
  import * as VAR5 from '@eslint-react/var';
6
6
  import { AST_NODE_TYPES } from '@typescript-eslint/types';
@@ -8,17 +8,18 @@ import { match } from 'ts-pattern';
8
8
 
9
9
  // package.json
10
10
  var name = "eslint-plugin-react-hooks-extra";
11
- var version = "1.23.3-next.8";
11
+ var version = "1.24.0-beta.1";
12
12
  var createRule = createRuleForPlugin("hooks-extra");
13
- function isFromHookCall(name2, context, settings, predicate = F.constTrue) {
13
+ function isFromHookCall(name2, context, settings, predicate = returnTrue) {
14
14
  const hookAlias = settings.additionalHooks?.[name2] ?? [];
15
- return (topLevelId) => F.pipe(
16
- VAR5.findVariable(topLevelId, context.sourceCode.getScope(topLevelId)),
17
- O.flatMap(VAR5.getVariableNode(0)),
18
- O.filter(AST2.is(AST_NODE_TYPES.CallExpression)),
19
- O.filter(isReactHookCallWithNameAlias(name2, context, hookAlias)),
20
- O.exists((call) => predicate(topLevelId, call))
21
- );
15
+ return (topLevelId) => {
16
+ const variable = VAR5.findVariable(topLevelId, context.sourceCode.getScope(topLevelId));
17
+ const variableNode = VAR5.getVariableNode(variable, 0);
18
+ if (variableNode == null) return false;
19
+ if (variableNode.type !== AST_NODE_TYPES.CallExpression) return false;
20
+ if (!isReactHookCallWithNameAlias(name2, context, hookAlias)(variableNode)) return false;
21
+ return predicate(topLevelId, variableNode);
22
+ };
22
23
  }
23
24
  function isFromUseStateCall(context, settings) {
24
25
  const predicate = (topLevelId, call) => {
@@ -49,8 +50,13 @@ function isSetFunctionCall(context, settings) {
49
50
  if (!isAt || index == null) {
50
51
  return false;
51
52
  }
52
- const initialScope = context.sourceCode.getScope(node);
53
- return O.exists(VAR5.getStaticValue(index, initialScope), (v) => v === 1) && isIdFromUseStateCall(callee.object);
53
+ const indexScope = context.sourceCode.getScope(node);
54
+ const indexValue = VAR5.toResolved({
55
+ kind: "lazy",
56
+ node: index,
57
+ initialScope: indexScope
58
+ }).value;
59
+ return indexValue === 1 && isIdFromUseStateCall(callee.object);
54
60
  }
55
61
  // const [data, setData] = useState();
56
62
  // setData();
@@ -63,8 +69,14 @@ function isSetFunctionCall(context, settings) {
63
69
  if (!("name" in node.callee.object)) {
64
70
  return false;
65
71
  }
66
- const initialScope = context.sourceCode.getScope(node);
67
- return O.exists(VAR5.getStaticValue(node.callee.property, initialScope), (v) => v === 1) && isIdFromUseStateCall(node.callee.object);
72
+ const property = node.callee.property;
73
+ const propertyScope = context.sourceCode.getScope(node);
74
+ const propertyValue = VAR5.toResolved({
75
+ kind: "lazy",
76
+ node: property,
77
+ initialScope: propertyScope
78
+ }).value;
79
+ return propertyValue === 1 && isIdFromUseStateCall(node.callee.object);
68
80
  }
69
81
  default: {
70
82
  return false;
@@ -125,8 +137,8 @@ var no_direct_set_state_in_use_effect_default = createRule({
125
137
  const isUseCallbackCall2 = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
126
138
  const isSetStateCall = isSetFunctionCall(context, settings);
127
139
  const isIdFromUseStateCall = isFromUseStateCall(context, settings);
128
- const functionStack = [];
129
- const setupFunctionRef = { current: O.none() };
140
+ const functionEntries = [];
141
+ const setupFunctionRef = { current: null };
130
142
  const setupFunctionIdentifiers = [];
131
143
  const indFunctionCalls = [];
132
144
  const indSetStateCalls = /* @__PURE__ */ new WeakMap();
@@ -134,10 +146,12 @@ var no_direct_set_state_in_use_effect_default = createRule({
134
146
  const indSetStateCallsInUseEffectSetup = /* @__PURE__ */ new Map();
135
147
  const indSetStateCallsInUseMemoOrCallback = /* @__PURE__ */ new WeakMap();
136
148
  const onSetupFunctionEnter = (node) => {
137
- setupFunctionRef.current = O.some(node);
149
+ setupFunctionRef.current = node;
138
150
  };
139
151
  const onSetupFunctionExit = (node) => {
140
- setupFunctionRef.current = O.filter(setupFunctionRef.current, (current) => current !== node);
152
+ if (setupFunctionRef.current === node) {
153
+ setupFunctionRef.current = null;
154
+ }
141
155
  };
142
156
  function isSetupFunction(node) {
143
157
  return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseEffectLikeCall(node.parent);
@@ -146,33 +160,30 @@ var no_direct_set_state_in_use_effect_default = createRule({
146
160
  return match(node).when(isUseStateCall2, () => "useState").when(isUseEffectLikeCall, () => "useEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
147
161
  }
148
162
  function getFunctionKind(node) {
149
- return match(node).when(isSetupFunction, () => "setup").when(AST2.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
163
+ return match(node).when(isSetupFunction, () => "setup").when(AST.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
150
164
  }
151
165
  return {
152
166
  ":function"(node) {
153
167
  const kind = getFunctionKind(node);
154
- functionStack.push({ kind, node });
168
+ functionEntries.push({ kind, node });
155
169
  if (kind === "setup") {
156
170
  onSetupFunctionEnter(node);
157
171
  }
158
172
  },
159
173
  ":function:exit"(node) {
160
- const { kind } = functionStack.at(-1) ?? {};
174
+ const { kind } = functionEntries.at(-1) ?? {};
161
175
  if (kind === "setup") {
162
176
  onSetupFunctionExit(node);
163
177
  }
164
- functionStack.pop();
178
+ functionEntries.pop();
165
179
  },
166
180
  CallExpression(node) {
167
- const setupFunction = O.getOrNull(setupFunctionRef.current);
168
- const pEntry = functionStack.at(-1);
169
- if (pEntry?.node.async) {
181
+ const setupFunction = setupFunctionRef.current;
182
+ const pEntry = functionEntries.at(-1);
183
+ if (pEntry == null || pEntry.node.async) {
170
184
  return;
171
185
  }
172
186
  match(getCallKind(node)).with("setState", () => {
173
- if (pEntry == null) {
174
- return;
175
- }
176
187
  switch (true) {
177
188
  case (pEntry.node === setupFunction || pEntry.kind === "immediate"): {
178
189
  context.report({
@@ -185,28 +196,28 @@ var no_direct_set_state_in_use_effect_default = createRule({
185
196
  return;
186
197
  }
187
198
  default: {
188
- const mbVariableDeclarator = AST2.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
189
- if (O.isNone(mbVariableDeclarator)) {
199
+ const variableDeclarator = AST.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
200
+ if (variableDeclarator == null) {
190
201
  const calls = indSetStateCalls.get(pEntry.node) ?? [];
191
202
  indSetStateCalls.set(pEntry.node, [...calls, node]);
192
203
  return;
193
204
  }
194
- const vd = mbVariableDeclarator.value;
195
- const prevs = indSetStateCallsInUseMemoOrCallback.get(vd.init) ?? [];
196
- indSetStateCallsInUseMemoOrCallback.set(vd.init, [...prevs, node]);
205
+ const init = variableDeclarator.init;
206
+ const prevs = indSetStateCallsInUseMemoOrCallback.get(init) ?? [];
207
+ indSetStateCallsInUseMemoOrCallback.set(init, [...prevs, node]);
197
208
  }
198
209
  }
199
210
  }).with("useEffect", () => {
200
- if (AST2.isFunction(node.arguments.at(0))) {
211
+ if (AST.isFunction(node.arguments.at(0))) {
201
212
  return;
202
213
  }
203
- setupFunctionIdentifiers.push(...AST2.getNestedIdentifiers(node));
214
+ setupFunctionIdentifiers.push(...AST.getNestedIdentifiers(node));
204
215
  }).with("other", () => {
205
- if (pEntry?.node !== setupFunction) {
216
+ if (pEntry.node !== setupFunction) {
206
217
  return;
207
218
  }
208
219
  indFunctionCalls.push(node);
209
- }).otherwise(F.constVoid);
220
+ }).otherwise(() => _);
210
221
  },
211
222
  Identifier(node) {
212
223
  if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) {
@@ -224,11 +235,10 @@ var no_direct_set_state_in_use_effect_default = createRule({
224
235
  if (!isUseMemoCall2(parent)) {
225
236
  break;
226
237
  }
227
- const mbVariableDeclarator = AST2.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
228
- if (O.isNone(mbVariableDeclarator)) {
238
+ const variableDeclarator = AST.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
239
+ if (variableDeclarator == null) {
229
240
  break;
230
241
  }
231
- const variableDeclarator = mbVariableDeclarator.value;
232
242
  const calls = indSetStateCallsInUseEffectArg0.get(variableDeclarator.init) ?? [];
233
243
  indSetStateCallsInUseEffectArg0.set(variableDeclarator.init, [...calls, node]);
234
244
  break;
@@ -238,11 +248,10 @@ var no_direct_set_state_in_use_effect_default = createRule({
238
248
  break;
239
249
  }
240
250
  if (isUseCallbackCall2(node.parent)) {
241
- const mbVariableDeclarator = AST2.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
242
- if (O.isNone(mbVariableDeclarator)) {
251
+ const variableDeclarator = AST.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
252
+ if (variableDeclarator == null) {
243
253
  break;
244
254
  }
245
- const variableDeclarator = mbVariableDeclarator.value;
246
255
  const prevs = indSetStateCallsInUseEffectArg0.get(variableDeclarator.init) ?? [];
247
256
  indSetStateCallsInUseEffectArg0.set(variableDeclarator.init, [...prevs, node]);
248
257
  }
@@ -256,7 +265,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
256
265
  },
257
266
  "Program:exit"() {
258
267
  const getSetStateCalls = (id, initialScope) => {
259
- const node = O.flatMap(VAR5.findVariable(id, initialScope), VAR5.getVariableNode(0)).pipe(O.getOrNull);
268
+ const node = VAR5.getVariableNode(VAR5.findVariable(id, initialScope), 0);
260
269
  switch (node?.type) {
261
270
  case AST_NODE_TYPES.ArrowFunctionExpression:
262
271
  case AST_NODE_TYPES.FunctionDeclaration:
@@ -267,7 +276,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
267
276
  }
268
277
  return [];
269
278
  };
270
- for (const [_, calls] of indSetStateCallsInUseEffectSetup) {
279
+ for (const [, calls] of indSetStateCallsInUseEffectSetup) {
271
280
  for (const call of calls) {
272
281
  context.report({
273
282
  messageId: "noDirectSetStateInUseEffect",
@@ -287,7 +296,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
287
296
  messageId: "noDirectSetStateInUseEffect",
288
297
  node: setStateCall,
289
298
  data: {
290
- name: AST2.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
299
+ name: AST.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
291
300
  }
292
301
  });
293
302
  }
@@ -299,7 +308,7 @@ var no_direct_set_state_in_use_effect_default = createRule({
299
308
  messageId: "noDirectSetStateInUseEffect",
300
309
  node: setStateCall,
301
310
  data: {
302
- name: AST2.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
311
+ name: AST.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
303
312
  }
304
313
  });
305
314
  }
@@ -342,8 +351,8 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
342
351
  const isUseCallbackCall2 = isReactHookCallWithNameAlias("useCallback", context, additionalHooks.useCallback ?? []);
343
352
  const isSetStateCall = isSetFunctionCall(context, settings);
344
353
  const isIdFromUseStateCall = isFromUseStateCall(context, settings);
345
- const functionStack = [];
346
- const setupFunctionRef = { current: O.none() };
354
+ const functionEntries = [];
355
+ const setupFunctionRef = { current: null };
347
356
  const setupFunctionIdentifiers = [];
348
357
  const indFunctionCalls = [];
349
358
  const indSetStateCalls = /* @__PURE__ */ new WeakMap();
@@ -351,10 +360,12 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
351
360
  const indSetStateCallsInUseLayoutEffectSetup = /* @__PURE__ */ new Map();
352
361
  const indSetStateCallsInUseMemoOrCallback = /* @__PURE__ */ new WeakMap();
353
362
  const onSetupFunctionEnter = (node) => {
354
- setupFunctionRef.current = O.some(node);
363
+ setupFunctionRef.current = node;
355
364
  };
356
365
  const onSetupFunctionExit = (node) => {
357
- setupFunctionRef.current = O.filter(setupFunctionRef.current, (current) => current !== node);
366
+ if (setupFunctionRef.current === node) {
367
+ setupFunctionRef.current = null;
368
+ }
358
369
  };
359
370
  function isSetupFunction(node) {
360
371
  return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && isUseLayoutEffectLikeCall(node.parent);
@@ -363,33 +374,30 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
363
374
  return match(node).when(isUseStateCall2, () => "useState").when(isUseLayoutEffectLikeCall, () => "useLayoutEffect").when(isSetStateCall, () => "setState").when(isThenCall, () => "then").otherwise(() => "other");
364
375
  }
365
376
  function getFunctionKind(node) {
366
- return match(node).when(isSetupFunction, () => "setup").when(AST2.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
377
+ return match(node).when(isSetupFunction, () => "setup").when(AST.isFunctionOfImmediatelyInvoked, () => "immediate").otherwise(() => "other");
367
378
  }
368
379
  return {
369
380
  ":function"(node) {
370
381
  const kind = getFunctionKind(node);
371
- functionStack.push({ kind, node });
382
+ functionEntries.push({ kind, node });
372
383
  if (kind === "setup") {
373
384
  onSetupFunctionEnter(node);
374
385
  }
375
386
  },
376
387
  ":function:exit"(node) {
377
- const { kind } = functionStack.at(-1) ?? {};
388
+ const { kind } = functionEntries.at(-1) ?? {};
378
389
  if (kind === "setup") {
379
390
  onSetupFunctionExit(node);
380
391
  }
381
- functionStack.pop();
392
+ functionEntries.pop();
382
393
  },
383
394
  CallExpression(node) {
384
- const setupFunction = O.getOrNull(setupFunctionRef.current);
385
- const pEntry = functionStack.at(-1);
386
- if (pEntry?.node.async) {
395
+ const setupFunction = setupFunctionRef.current;
396
+ const pEntry = functionEntries.at(-1);
397
+ if (pEntry == null || pEntry.node.async) {
387
398
  return;
388
399
  }
389
400
  match(getCallKind(node)).with("setState", () => {
390
- if (pEntry == null) {
391
- return;
392
- }
393
401
  switch (true) {
394
402
  case (pEntry.node === setupFunction || pEntry.kind === "immediate"): {
395
403
  context.report({
@@ -402,28 +410,28 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
402
410
  return;
403
411
  }
404
412
  default: {
405
- const mbVariableDeclarator = AST2.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
406
- if (O.isNone(mbVariableDeclarator)) {
413
+ const variableDeclarator = AST.findParentNodeGuard(node, isVariableDeclaratorFromHookCall);
414
+ if (variableDeclarator == null) {
407
415
  const calls = indSetStateCalls.get(pEntry.node) ?? [];
408
416
  indSetStateCalls.set(pEntry.node, [...calls, node]);
409
417
  return;
410
418
  }
411
- const vd = mbVariableDeclarator.value;
412
- const prevs = indSetStateCallsInUseMemoOrCallback.get(vd.init) ?? [];
413
- indSetStateCallsInUseMemoOrCallback.set(vd.init, [...prevs, node]);
419
+ const init = variableDeclarator.init;
420
+ const prevs = indSetStateCallsInUseMemoOrCallback.get(init) ?? [];
421
+ indSetStateCallsInUseMemoOrCallback.set(init, [...prevs, node]);
414
422
  }
415
423
  }
416
424
  }).with("useLayoutEffect", () => {
417
- if (AST2.isFunction(node.arguments.at(0))) {
425
+ if (AST.isFunction(node.arguments.at(0))) {
418
426
  return;
419
427
  }
420
- setupFunctionIdentifiers.push(...AST2.getNestedIdentifiers(node));
428
+ setupFunctionIdentifiers.push(...AST.getNestedIdentifiers(node));
421
429
  }).with("other", () => {
422
- if (pEntry?.node !== setupFunction) {
430
+ if (pEntry.node !== setupFunction) {
423
431
  return;
424
432
  }
425
433
  indFunctionCalls.push(node);
426
- }).otherwise(F.constVoid);
434
+ }).otherwise(() => _);
427
435
  },
428
436
  Identifier(node) {
429
437
  if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) {
@@ -441,11 +449,10 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
441
449
  if (!isUseMemoCall2(parent)) {
442
450
  break;
443
451
  }
444
- const mbVariableDeclarator = AST2.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
445
- if (O.isNone(mbVariableDeclarator)) {
452
+ const variableDeclarator = AST.findParentNodeGuard(parent, isVariableDeclaratorFromHookCall);
453
+ if (variableDeclarator == null) {
446
454
  break;
447
455
  }
448
- const variableDeclarator = mbVariableDeclarator.value;
449
456
  const calls = indSetStateCallsInUseLayoutEffectArg0.get(variableDeclarator.init) ?? [];
450
457
  indSetStateCallsInUseLayoutEffectArg0.set(variableDeclarator.init, [...calls, node]);
451
458
  break;
@@ -455,11 +462,10 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
455
462
  break;
456
463
  }
457
464
  if (isUseCallbackCall2(node.parent)) {
458
- const mbVariableDeclarator = AST2.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
459
- if (O.isNone(mbVariableDeclarator)) {
465
+ const variableDeclarator = AST.findParentNodeGuard(node.parent, isVariableDeclaratorFromHookCall);
466
+ if (variableDeclarator == null) {
460
467
  break;
461
468
  }
462
- const variableDeclarator = mbVariableDeclarator.value;
463
469
  const prevs = indSetStateCallsInUseLayoutEffectArg0.get(variableDeclarator.init) ?? [];
464
470
  indSetStateCallsInUseLayoutEffectArg0.set(variableDeclarator.init, [...prevs, node]);
465
471
  }
@@ -473,7 +479,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
473
479
  },
474
480
  "Program:exit"() {
475
481
  const getSetStateCalls = (id, initialScope) => {
476
- const node = O.flatMap(VAR5.findVariable(id, initialScope), VAR5.getVariableNode(0)).pipe(O.getOrNull);
482
+ const node = VAR5.getVariableNode(VAR5.findVariable(id, initialScope), 0);
477
483
  switch (node?.type) {
478
484
  case AST_NODE_TYPES.ArrowFunctionExpression:
479
485
  case AST_NODE_TYPES.FunctionDeclaration:
@@ -484,7 +490,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
484
490
  }
485
491
  return [];
486
492
  };
487
- for (const [_, calls] of indSetStateCallsInUseLayoutEffectSetup) {
493
+ for (const [, calls] of indSetStateCallsInUseLayoutEffectSetup) {
488
494
  for (const call of calls) {
489
495
  context.report({
490
496
  messageId: "noDirectSetStateInUseLayoutEffect",
@@ -504,7 +510,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
504
510
  messageId: "noDirectSetStateInUseLayoutEffect",
505
511
  node: setStateCall,
506
512
  data: {
507
- name: AST2.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
513
+ name: AST.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
508
514
  }
509
515
  });
510
516
  }
@@ -516,7 +522,7 @@ var no_direct_set_state_in_use_layout_effect_default = createRule({
516
522
  messageId: "noDirectSetStateInUseLayoutEffect",
517
523
  node: setStateCall,
518
524
  data: {
519
- name: AST2.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
525
+ name: AST.toReadableNodeName(setStateCall, (n) => context.sourceCode.getText(n))
520
526
  }
521
527
  });
522
528
  }
@@ -559,43 +565,41 @@ var no_unnecessary_use_callback_default = createRule({
559
565
  }
560
566
  const scope = context.sourceCode.getScope(node);
561
567
  const component = scope.block;
562
- if (!AST2.isFunction(component)) {
568
+ if (!AST.isFunction(component)) {
563
569
  return;
564
570
  }
565
571
  const [arg0, arg1] = node.arguments;
566
572
  if (arg0 == null || arg1 == null) {
567
573
  return;
568
574
  }
569
- const hasEmptyDeps = F.pipe(
570
- match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
571
- return F.pipe(
572
- VAR5.findVariable(n.name, initialScope),
573
- O.flatMap(VAR5.getVariableNode(0)),
574
- O.filter(AST2.is(AST_NODE_TYPES.ArrayExpression))
575
- );
576
- }).otherwise(O.none),
577
- O.exists((x) => x.elements.length === 0)
578
- );
575
+ const hasEmptyDeps = match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
576
+ const variable = VAR5.findVariable(n.name, initialScope);
577
+ const variableNode = VAR5.getVariableNode(variable, 0);
578
+ if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) {
579
+ return false;
580
+ }
581
+ return variableNode.elements.length === 0;
582
+ }).otherwise(() => false);
579
583
  if (!hasEmptyDeps) {
580
584
  return;
581
585
  }
582
- const isReferencedToComponentScope = F.pipe(
583
- match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
584
- if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
585
- return O.some(n.body);
586
- }
587
- return O.some(n);
588
- }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
589
- return F.pipe(
590
- VAR5.findVariable(n.name, initialScope),
591
- O.flatMap(VAR5.getVariableNode(0)),
592
- O.filter(AST2.isFunction)
593
- );
594
- }).otherwise(O.none),
595
- O.map((n) => context.sourceCode.getScope(n)),
596
- O.map((s) => VAR5.getChidScopes(s).flatMap((x) => x.references)),
597
- O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
598
- );
586
+ const arg0Node = match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
587
+ if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
588
+ return n.body;
589
+ }
590
+ return n;
591
+ }).with({ type: AST_NODE_TYPES.FunctionExpression }, identity).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
592
+ const variable = VAR5.findVariable(n.name, initialScope);
593
+ const variableNode = VAR5.getVariableNode(variable, 0);
594
+ if (variableNode?.type !== AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== AST_NODE_TYPES.FunctionExpression) {
595
+ return _;
596
+ }
597
+ return variableNode;
598
+ }).otherwise(() => _);
599
+ if (arg0Node == null) return;
600
+ const arg0NodeScope = context.sourceCode.getScope(arg0Node);
601
+ const arg0NodeReferences = VAR5.getChidScopes(arg0NodeScope).flatMap((x) => x.references);
602
+ const isReferencedToComponentScope = arg0NodeReferences.some((x) => x.resolved?.scope.block === component);
599
603
  if (!isReferencedToComponentScope) {
600
604
  context.report({
601
605
  messageId: "noUnnecessaryUseCallback",
@@ -640,51 +644,45 @@ var no_unnecessary_use_memo_default = createRule({
640
644
  }
641
645
  const scope = context.sourceCode.getScope(node);
642
646
  const component = scope.block;
643
- if (!AST2.isFunction(component)) {
647
+ if (!AST.isFunction(component)) {
644
648
  return;
645
649
  }
646
650
  const [arg0, arg1] = node.arguments;
647
651
  if (arg0 == null || arg1 == null) {
648
652
  return;
649
653
  }
650
- const hasCallInArg0 = F.pipe(
651
- O.some(arg0),
652
- O.filter((n) => AST2.isFunction(n)),
653
- O.exists((n) => [...AST2.getNestedCallExpressions(n.body), ...AST2.getNestedNewExpressions(n.body)].length > 0)
654
- );
654
+ const hasCallInArg0 = AST.isFunction(arg0) && [...AST.getNestedCallExpressions(arg0.body), ...AST.getNestedNewExpressions(arg0.body)].length > 0;
655
655
  if (hasCallInArg0) {
656
656
  return;
657
657
  }
658
- const hasEmptyDeps = F.pipe(
659
- match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
660
- return F.pipe(
661
- VAR5.findVariable(n.name, initialScope),
662
- O.flatMap(VAR5.getVariableNode(0)),
663
- O.filter(AST2.is(AST_NODE_TYPES.ArrayExpression))
664
- );
665
- }).otherwise(O.none),
666
- O.exists((x) => x.elements.length === 0)
667
- );
658
+ const hasEmptyDeps = match(arg1).with({ type: AST_NODE_TYPES.ArrayExpression }, (n) => n.elements.length === 0).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
659
+ const variable = VAR5.findVariable(n.name, initialScope);
660
+ const variableNode = VAR5.getVariableNode(variable, 0);
661
+ if (variableNode?.type !== AST_NODE_TYPES.ArrayExpression) {
662
+ return false;
663
+ }
664
+ return variableNode.elements.length === 0;
665
+ }).otherwise(() => false);
668
666
  if (!hasEmptyDeps) {
669
667
  return;
670
668
  }
671
- const isReferencedToComponentScope = F.pipe(
672
- match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
673
- if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
674
- return O.some(n.body);
675
- }
676
- return O.some(n);
677
- }).with({ type: AST_NODE_TYPES.FunctionExpression }, O.some).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
678
- return F.pipe(
679
- VAR5.findVariable(n.name, initialScope),
680
- O.flatMap(VAR5.getVariableNode(0)),
681
- O.filter(AST2.isFunction)
682
- );
683
- }).otherwise(O.none),
684
- O.map((n) => context.sourceCode.getScope(n)),
685
- O.map((s) => VAR5.getChidScopes(s).flatMap((x) => x.references)),
686
- O.exists((refs) => refs.some((x) => x.resolved?.scope.block === component))
687
- );
669
+ const arg0Node = match(arg0).with({ type: AST_NODE_TYPES.ArrowFunctionExpression }, (n) => {
670
+ if (n.body.type === AST_NODE_TYPES.ArrowFunctionExpression) {
671
+ return n.body;
672
+ }
673
+ return n;
674
+ }).with({ type: AST_NODE_TYPES.FunctionExpression }, identity).with({ type: AST_NODE_TYPES.Identifier }, (n) => {
675
+ const variable = VAR5.findVariable(n.name, initialScope);
676
+ const variableNode = VAR5.getVariableNode(variable, 0);
677
+ if (variableNode?.type !== AST_NODE_TYPES.ArrowFunctionExpression && variableNode?.type !== AST_NODE_TYPES.FunctionExpression) {
678
+ return _;
679
+ }
680
+ return variableNode;
681
+ }).otherwise(() => _);
682
+ if (arg0Node == null) return;
683
+ const arg0NodeScope = context.sourceCode.getScope(arg0Node);
684
+ const arg0NodeReferences = VAR5.getChidScopes(arg0NodeScope).flatMap((x) => x.references);
685
+ const isReferencedToComponentScope = arg0NodeReferences.some((x) => x.resolved?.scope.block === component);
688
686
  if (!isReferencedToComponentScope) {
689
687
  context.report({
690
688
  messageId: "noUnnecessaryUseMemo",
@@ -723,7 +721,7 @@ var no_useless_custom_hooks_default = createRule({
723
721
  "Program:exit"(node) {
724
722
  const allHooks = ctx.getAllHooks(node);
725
723
  for (const { name: name2, node: node2, hookCalls } of allHooks.values()) {
726
- if (AST2.isEmptyFunction(node2)) {
724
+ if (AST.isEmptyFunction(node2)) {
727
725
  continue;
728
726
  }
729
727
  if (hookCalls.length > 0) {
@@ -736,7 +734,7 @@ var no_useless_custom_hooks_default = createRule({
736
734
  messageId: "noUselessCustomHooks",
737
735
  node: node2,
738
736
  data: {
739
- name: name2.value
737
+ name: name2
740
738
  }
741
739
  });
742
740
  }
@@ -780,11 +778,11 @@ var prefer_use_state_lazy_initialization_default = createRule({
780
778
  if (useStateInput == null) {
781
779
  return;
782
780
  }
783
- const nestedCallExpressions = AST2.getNestedCallExpressions(useStateInput);
781
+ const nestedCallExpressions = AST.getNestedCallExpressions(useStateInput);
784
782
  const hasFunctionCall = nestedCallExpressions.some((n) => {
785
783
  return "name" in n.callee && !ALLOW_LIST.includes(n.callee.name);
786
784
  });
787
- const hasNewCall = AST2.getNestedNewExpressions(useStateInput).some((n) => {
785
+ const hasNewCall = AST.getNestedNewExpressions(useStateInput).some((n) => {
788
786
  return "name" in n.callee && !ALLOW_LIST.includes(n.callee.name);
789
787
  });
790
788
  if (!hasFunctionCall && !hasNewCall) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks-extra",
3
- "version": "1.23.3-next.8",
3
+ "version": "1.24.0-beta.1",
4
4
  "description": "ESLint React's ESLint plugin for React Hooks related rules.",
5
5
  "keywords": [
6
6
  "react",
@@ -11,13 +11,13 @@
11
11
  "eslint-plugin",
12
12
  "eslint-plugin-react-hooks-extra"
13
13
  ],
14
- "homepage": "https://github.com/rEl1cx/eslint-react",
14
+ "homepage": "https://github.com/Rel1cx/eslint-react",
15
15
  "bugs": {
16
- "url": "https://github.com/rEl1cx/eslint-react/issues"
16
+ "url": "https://github.com/Rel1cx/eslint-react/issues"
17
17
  },
18
18
  "repository": {
19
19
  "type": "git",
20
- "url": "git+https://github.com/rEl1cx/eslint-react.git",
20
+ "url": "git+https://github.com/Rel1cx/eslint-react.git",
21
21
  "directory": "packages/plugins/eslint-plugin-react-hooks-extra"
22
22
  },
23
23
  "license": "MIT",
@@ -48,17 +48,17 @@
48
48
  "@typescript-eslint/utils": "^8.19.1",
49
49
  "string-ts": "^2.2.0",
50
50
  "ts-pattern": "^5.6.0",
51
- "@eslint-react/ast": "1.23.3-next.8",
52
- "@eslint-react/jsx": "1.23.3-next.8",
53
- "@eslint-react/core": "1.23.3-next.8",
54
- "@eslint-react/shared": "1.23.3-next.8",
55
- "@eslint-react/types": "1.23.3-next.8",
56
- "@eslint-react/var": "1.23.3-next.8",
57
- "@eslint-react/eff": "1.23.3-next.8"
51
+ "@eslint-react/ast": "1.24.0-beta.1",
52
+ "@eslint-react/eff": "1.24.0-beta.1",
53
+ "@eslint-react/jsx": "1.24.0-beta.1",
54
+ "@eslint-react/shared": "1.24.0-beta.1",
55
+ "@eslint-react/var": "1.24.0-beta.1",
56
+ "@eslint-react/core": "1.24.0-beta.1",
57
+ "@eslint-react/types": "1.24.0-beta.1"
58
58
  },
59
59
  "devDependencies": {
60
- "@types/react": "^19.0.4",
61
- "@types/react-dom": "^19.0.2",
60
+ "@types/react": "^19.0.5",
61
+ "@types/react-dom": "^19.0.3",
62
62
  "tsup": "^8.3.5",
63
63
  "@workspace/configs": "0.0.0"
64
64
  },