eslint-plugin-react-hooks-extra 1.5.26-beta.1 → 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/dist/index.js CHANGED
@@ -9,7 +9,7 @@ var astUtils = require('@typescript-eslint/utils/ast-utils');
9
9
 
10
10
  // package.json
11
11
  var name = "eslint-plugin-react-hooks-extra";
12
- var version = "1.5.26-beta.1";
12
+ var version = "1.5.26-beta.2";
13
13
  var createRule = shared.createRuleForPlugin("hooks-extra");
14
14
 
15
15
  // src/rules/ensure-custom-hooks-using-other-hooks.ts
@@ -227,7 +227,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
227
227
  description: "enforce 'useCallback' has non-empty dependencies array"
228
228
  },
229
229
  messages: {
230
- 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."
231
231
  },
232
232
  schema: []
233
233
  },
@@ -236,12 +236,15 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
236
236
  const alias = shared.getESLintReactSettings(context.settings).additionalHooks?.useCallback ?? [];
237
237
  return {
238
238
  CallExpression(node) {
239
- const initialScope = context.sourceCode.getScope(node);
240
239
  if (!core.isReactHookCall(node)) return;
240
+ const initialScope = context.sourceCode.getScope(node);
241
241
  if (!core.isUseCallbackCall(node, context) && !alias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node))) {
242
242
  return;
243
243
  }
244
- const [_2, deps] = node.arguments;
244
+ const scope = context.sourceCode.getScope(node);
245
+ const component = scope.block;
246
+ if (!ast.isFunction(component)) return;
247
+ const [cb, deps] = node.arguments;
245
248
  if (!deps) {
246
249
  context.report({
247
250
  messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
@@ -249,7 +252,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
249
252
  });
250
253
  return;
251
254
  }
252
- const maybeDescriptor = tools.F.pipe(
255
+ const hasEmptyDeps = tools.F.pipe(
253
256
  $(deps).with({ type: ast.NodeType.ArrayExpression }, tools.O.some).with({ type: ast.NodeType.Identifier }, (n2) => {
254
257
  return tools.F.pipe(
255
258
  _var.findVariable(n2.name, initialScope),
@@ -257,13 +260,32 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
257
260
  tools.O.filter(ast.is(ast.NodeType.ArrayExpression))
258
261
  );
259
262
  }).otherwise(tools.O.none),
260
- tools.O.filter((x2) => x2.elements.length === 0),
261
- tools.O.map(() => ({
263
+ tools.O.exists((x2) => x2.elements.length === 0)
264
+ );
265
+ if (!hasEmptyDeps) return;
266
+ if (!cb) {
267
+ context.report({
262
268
  messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
263
269
  node
264
- }))
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))
265
283
  );
266
- tools.O.map(maybeDescriptor, context.report);
284
+ if (isReferencedToComponentScope) return;
285
+ context.report({
286
+ messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
287
+ node
288
+ });
267
289
  }
268
290
  };
269
291
  },
@@ -277,7 +299,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
277
299
  description: "enforce 'useMemo' has non-empty dependencies array"
278
300
  },
279
301
  messages: {
280
- 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."
281
303
  },
282
304
  schema: []
283
305
  },
@@ -286,10 +308,15 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
286
308
  const alias = shared.getESLintReactSettings(context.settings).additionalHooks?.useMemo ?? [];
287
309
  return {
288
310
  CallExpression(node) {
289
- const initialScope = context.sourceCode.getScope(node);
290
311
  if (!core.isReactHookCall(node)) return;
291
- if (!core.isUseMemoCall(node, context) && !alias.some(tools.F.flip(core.isReactHookCallWithNameLoose)(node))) return;
292
- const [_2, deps] = node.arguments;
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;
293
320
  if (!deps) {
294
321
  context.report({
295
322
  messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
@@ -297,7 +324,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
297
324
  });
298
325
  return;
299
326
  }
300
- const maybeDescriptor = tools.F.pipe(
327
+ const hasEmptyDeps = tools.F.pipe(
301
328
  $(deps).with({ type: ast.NodeType.ArrayExpression }, tools.O.some).with({ type: ast.NodeType.Identifier }, (n2) => {
302
329
  return tools.F.pipe(
303
330
  _var.findVariable(n2.name, initialScope),
@@ -305,13 +332,32 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
305
332
  tools.O.filter(ast.is(ast.NodeType.ArrayExpression))
306
333
  );
307
334
  }).otherwise(tools.O.none),
308
- tools.O.filter((x2) => x2.elements.length === 0),
309
- tools.O.map(() => ({
335
+ tools.O.exists((x2) => x2.elements.length === 0)
336
+ );
337
+ if (!hasEmptyDeps) return;
338
+ if (!cb) {
339
+ context.report({
310
340
  messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
311
341
  node
312
- }))
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))
313
355
  );
314
- tools.O.map(maybeDescriptor, context.report);
356
+ if (isReferencedToComponentScope) return;
357
+ context.report({
358
+ messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
359
+ node
360
+ });
315
361
  }
316
362
  };
317
363
  },
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import { useHookCollector, isReactHookCall, isUseCallbackCall, isReactHookCallWithNameLoose, isUseMemoCall, isUseStateCall, isUseEffectCall, isUseLayoutEffectCall } from '@eslint-react/core';
2
2
  import { createRuleForPlugin, getESLintReactSettings } from '@eslint-react/shared';
3
- import { NodeType, is, traverseUp, 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
6
  import { getStaticValue } from '@typescript-eslint/utils/ast-utils';
7
7
 
8
8
  // package.json
9
9
  var name = "eslint-plugin-react-hooks-extra";
10
- var version = "1.5.26-beta.1";
10
+ var version = "1.5.26-beta.2";
11
11
  var createRule = createRuleForPlugin("hooks-extra");
12
12
 
13
13
  // src/rules/ensure-custom-hooks-using-other-hooks.ts
@@ -225,7 +225,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
225
225
  description: "enforce 'useCallback' has non-empty dependencies array"
226
226
  },
227
227
  messages: {
228
- 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."
229
229
  },
230
230
  schema: []
231
231
  },
@@ -234,12 +234,15 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
234
234
  const alias = getESLintReactSettings(context.settings).additionalHooks?.useCallback ?? [];
235
235
  return {
236
236
  CallExpression(node) {
237
- const initialScope = context.sourceCode.getScope(node);
238
237
  if (!isReactHookCall(node)) return;
238
+ const initialScope = context.sourceCode.getScope(node);
239
239
  if (!isUseCallbackCall(node, context) && !alias.some(F.flip(isReactHookCallWithNameLoose)(node))) {
240
240
  return;
241
241
  }
242
- const [_2, deps] = node.arguments;
242
+ const scope = context.sourceCode.getScope(node);
243
+ const component = scope.block;
244
+ if (!isFunction(component)) return;
245
+ const [cb, deps] = node.arguments;
243
246
  if (!deps) {
244
247
  context.report({
245
248
  messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
@@ -247,7 +250,7 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
247
250
  });
248
251
  return;
249
252
  }
250
- const maybeDescriptor = F.pipe(
253
+ const hasEmptyDeps = F.pipe(
251
254
  $(deps).with({ type: NodeType.ArrayExpression }, O.some).with({ type: NodeType.Identifier }, (n2) => {
252
255
  return F.pipe(
253
256
  findVariable(n2.name, initialScope),
@@ -255,13 +258,32 @@ var ensure_use_callback_has_non_empty_deps_default = createRule({
255
258
  O.filter(is(NodeType.ArrayExpression))
256
259
  );
257
260
  }).otherwise(O.none),
258
- O.filter((x2) => x2.elements.length === 0),
259
- O.map(() => ({
261
+ O.exists((x2) => x2.elements.length === 0)
262
+ );
263
+ if (!hasEmptyDeps) return;
264
+ if (!cb) {
265
+ context.report({
260
266
  messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
261
267
  node
262
- }))
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))
263
281
  );
264
- O.map(maybeDescriptor, context.report);
282
+ if (isReferencedToComponentScope) return;
283
+ context.report({
284
+ messageId: "ENSURE_USE_CALLBACK_HAS_NON_EMPTY_DEPS",
285
+ node
286
+ });
265
287
  }
266
288
  };
267
289
  },
@@ -275,7 +297,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
275
297
  description: "enforce 'useMemo' has non-empty dependencies array"
276
298
  },
277
299
  messages: {
278
- 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."
279
301
  },
280
302
  schema: []
281
303
  },
@@ -284,10 +306,15 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
284
306
  const alias = getESLintReactSettings(context.settings).additionalHooks?.useMemo ?? [];
285
307
  return {
286
308
  CallExpression(node) {
287
- const initialScope = context.sourceCode.getScope(node);
288
309
  if (!isReactHookCall(node)) return;
289
- if (!isUseMemoCall(node, context) && !alias.some(F.flip(isReactHookCallWithNameLoose)(node))) return;
290
- const [_2, deps] = node.arguments;
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;
291
318
  if (!deps) {
292
319
  context.report({
293
320
  messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
@@ -295,7 +322,7 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
295
322
  });
296
323
  return;
297
324
  }
298
- const maybeDescriptor = F.pipe(
325
+ const hasEmptyDeps = F.pipe(
299
326
  $(deps).with({ type: NodeType.ArrayExpression }, O.some).with({ type: NodeType.Identifier }, (n2) => {
300
327
  return F.pipe(
301
328
  findVariable(n2.name, initialScope),
@@ -303,13 +330,32 @@ var ensure_use_memo_has_non_empty_deps_default = createRule({
303
330
  O.filter(is(NodeType.ArrayExpression))
304
331
  );
305
332
  }).otherwise(O.none),
306
- O.filter((x2) => x2.elements.length === 0),
307
- O.map(() => ({
333
+ O.exists((x2) => x2.elements.length === 0)
334
+ );
335
+ if (!hasEmptyDeps) return;
336
+ if (!cb) {
337
+ context.report({
308
338
  messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
309
339
  node
310
- }))
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))
311
353
  );
312
- O.map(maybeDescriptor, context.report);
354
+ if (isReferencedToComponentScope) return;
355
+ context.report({
356
+ messageId: "ENSURE_USE_MEMO_HAS_NON_EMPTY_DEPS",
357
+ node
358
+ });
313
359
  }
314
360
  };
315
361
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks-extra",
3
- "version": "1.5.26-beta.1",
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/ast": "1.5.26-beta.1",
43
- "@eslint-react/tools": "1.5.26-beta.1",
44
- "@eslint-react/shared": "1.5.26-beta.1",
45
- "@eslint-react/types": "1.5.26-beta.1",
46
- "@eslint-react/core": "1.5.26-beta.1",
47
- "@eslint-react/var": "1.5.26-beta.1",
48
- "@eslint-react/jsx": "1.5.26-beta.1"
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",