Repository: eslint-functional/eslint-plugin-functional
Pull request #802 (2024-04-14 05:40:56)

fix(prefer-tacit): handling functions that don't map to directly to an eslint node
Fix 801

RebeccaStevens: * **#802** <a href="https://app.graphite.dev/github/pr/eslint-functional/eslint-plugin-functional/802?utm_source=stack-comment-icon" target="_blank"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="10px" height="10px"/></a> 👈
* `main`

This stack of pull requests is managed by Graphite. <a href="https://stacking.dev/?utm_source=stack-comment">Learn more about stacking.</a>
<h2></h2>

 Join @RebeccaStevens and the rest of your teammates on <a href="https://graphite.dev?utm-source=stack-comment"><img src="https://static.graphite.dev/graphite-32x32-black.png" alt="Graphite" width="11px" height="11px"/> <b>Graphite</b></a>
  <!-- Current dependencies on/for this PR: -->

Patch:
diff --git a/src/rules/prefer-tacit.ts b/src/rules/prefer-tacit.ts
index 1e16cd0..e137dbc 100644
--- a/src/rules/prefer-tacit.ts
+++ b/src/rules/prefer-tacit.ts
@@ -15,8 +15,8 @@ import { ruleNameScope } from "#eslint-plugin-functional/utils/misc";
 import { type ESFunction } from "#eslint-plugin-functional/utils/node-types";
 import {
   createRule,
-  getESTreeNode,
   getTypeOfNode,
+  getTypeOfTSNode,
   type NamedCreateRuleCustomMeta,
   type RuleResult,
 } from "#eslint-plugin-functional/utils/rule";
@@ -24,11 +24,8 @@ import { isNested } from "#eslint-plugin-functional/utils/tree";
 import {
   isBlockStatement,
   isCallExpression,
-  isDefined,
-  isFunctionLike,
   isIdentifier,
   isReturnStatement,
-  isTSFunctionType,
 } from "#eslint-plugin-functional/utils/type-guards";
 
 /**
@@ -106,13 +103,12 @@ function isCallerViolation(
   if (tsDeclaration === undefined) {
     return false;
   }
-  const declaration = getESTreeNode(tsDeclaration, context);
 
-  return (
-    isDefined(declaration) &&
-    (isFunctionLike(declaration) || isTSFunctionType(declaration)) &&
-    declaration.params.length === caller.arguments.length
-  );
+  return getTypeOfTSNode(tsDeclaration, context)
+    .getCallSignatures()
+    .some(
+      (signature) => signature.parameters.length === caller.arguments.length,
+    );
 }
 
 /**
diff --git a/src/utils/rule.ts b/src/utils/rule.ts
index e83b4ec..49d4be3 100644
--- a/src/utils/rule.ts
+++ b/src/utils/rule.ts
@@ -188,12 +188,22 @@ export function getTypeOfNode<Context extends RuleContext<string, BaseOptions>>(
   node: TSESTree.Node,
   context: Context,
 ): Type {
-  const parserServices = getParserServices(context);
+  const { esTreeNodeToTSNodeMap } = getParserServices(context);
 
-  const checker = parserServices.program.getTypeChecker();
-  const { esTreeNodeToTSNodeMap } = parserServices;
+  const tsNode = esTreeNodeToTSNodeMap.get(node);
+  return getTypeOfTSNode(tsNode, context);
+}
+
+/**
+ * Get the type of the the given ts node.
+ */
+export function getTypeOfTSNode<
+  Context extends RuleContext<string, BaseOptions>,
+>(node: TSNode, context: Context): Type {
+  const { program } = getParserServices(context);
+  const checker = program.getTypeChecker();
 
-  const nodeType = checker.getTypeAtLocation(esTreeNodeToTSNodeMap.get(node));
+  const nodeType = checker.getTypeAtLocation(node);
   const constrained = checker.getBaseConstraintOfType(nodeType);
   return constrained ?? nodeType;
 }


Test patch:
diff --git a/tests/rules/prefer-tacit/ts/invalid.ts b/tests/rules/prefer-tacit/ts/invalid.ts
index 37ca542..be77950 100644
--- a/tests/rules/prefer-tacit/ts/invalid.ts
+++ b/tests/rules/prefer-tacit/ts/invalid.ts
@@ -237,6 +237,29 @@ const tests: Array<
       },
     ],
   },
+  // Boolean constructor
+  {
+    code: dedent`
+      const foo = [1, 2, 3].map(x => Boolean(x));
+    `,
+    optionsSet: [[]],
+    errors: [
+      {
+        messageId: "generic",
+        type: AST_NODE_TYPES.ArrowFunctionExpression,
+        line: 1,
+        column: 27,
+        suggestions: [
+          {
+            messageId: "generic",
+            output: dedent`
+            const foo = [1, 2, 3].map(Boolean);
+          `,
+          },
+        ],
+      },
+    ],
+  },
   // Instantiation Expression not supported.
   {
     code: dedent`