Repository: typescript-eslint/tslint-to-eslint-config (ts)

Issue:
Missing Converter for typedef
<!--
👋 Hi, thanks for filing an issue on tslint-to-eslint-config! 💖
Please fill out all fields below to ensure your issue is addressed.

If your issue doesn't provide enough info to fully explain or reproduce your bug, it will be closed. 😦
-->

### 💥 Missing Converter

-   `tslint-to-eslint-config` version: 2.1.0
-   `typescript-eslint` version: 4.14.1

#### TSLint Rule Name

  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint's "typedef".

#### Package Source

https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/typedef.md

Pull request description:
Add converter for `typedef` property 
<!--
👋 Hi, thanks for sending a PR to tslint-to-eslint-config! 💖
Please fill out all fields below to ensure your PR is reviewed quickly.
-->
Hoi! ^w^ :wave:

## PR Checklist

-   [x] Fixes #937
-   [x] That issue was marked as [`status: accepting prs`](https://github.com/typescript-eslint/tslint-to-eslint-config/labels/status%3A%20accepting%20prs)

## Overview

The [typedef](https://palantir.github.io/tslint/rules/typedef/) property of TSLint is now considered during the conversion. All config options except `call-signature` and `arrow-call-signature` are accounted for. Options unaccounted for are mentioned in the `notices` array, when applicable

The linked issue and the [ESLint typedef docs](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/typedef.md) mentions that [explicit-function-return-type](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/explicit-function-return-type.md) and [explicit-module-boundary-types](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md) should be used when converting `call-signature` and `arrow-call-signature`. I did that in a separate branch [here](https://github.com/hyperupcall/tslint-to-eslint-config/commit/b99f54eaa8a4bc1e1fe0729b6b80d5069f77572d), but I wasn't 100% confident that my conversion was correct, so I left it out for now. If it is close to what is considered acceptable, maybe I can add it to this PR?

I'll also add that I had to install `@swc/core` to get things to run, despite [this](65f9090345b31f22371fcdffea22be5b833cbe2dc) mentioning its not required - not sure what's up with that. Also the Docs say Node 12 works, but 14 was the minimum LTS that worked for me (Jest threw `SyntaxError: Unexpected token '.'` when it encountered optional chaining) 

Patch:
diff --git a/src/converters/lintConfigs/rules/ruleConverters.ts b/src/converters/lintConfigs/rules/ruleConverters.ts
index e83453f..51c9a34 100644
--- a/src/converters/lintConfigs/rules/ruleConverters.ts
+++ b/src/converters/lintConfigs/rules/ruleConverters.ts
@@ -321,6 +321,7 @@ import { convertTemplateUseTrackByFunction } from "./ruleConverters/template-use
 import { convertTrailingComma } from "./ruleConverters/trailing-comma";
 import { convertTripleEquals } from "./ruleConverters/triple-equals";
 import { convertTypeLiteralDelimiter } from "./ruleConverters/type-literal-delimiter";
+import { convertTypedef } from "./ruleConverters/typedef";
 import { convertTypedefWhitespace } from "./ruleConverters/typedef-whitespace";
 import { convertTypeofCompare } from "./ruleConverters/typeof-compare";
 import { convertUnderscoreConsistentInvocation } from "./ruleConverters/underscore-consistent-invocation";
@@ -669,6 +670,7 @@ export const ruleConverters = new Map([
     ["trailing-comma", convertTrailingComma],
     ["triple-equals", convertTripleEquals],
     ["type-literal-delimiter", convertTypeLiteralDelimiter],
+    ["typedef", convertTypedef],
     ["typedef-whitespace", convertTypedefWhitespace],
     ["typeof-compare", convertTypeofCompare],
     ["underscore-consistent-invocation", convertUnderscoreConsistentInvocation],
diff --git a/src/converters/lintConfigs/rules/ruleConverters/typedef.ts b/src/converters/lintConfigs/rules/ruleConverters/typedef.ts
new file mode 100644
index 0000000..b0a5cb8
--- /dev/null
+++ b/src/converters/lintConfigs/rules/ruleConverters/typedef.ts
@@ -0,0 +1,67 @@
+import { RuleConverter } from "../ruleConverter";
+
+export const convertTypedef: RuleConverter = (tslintRule) => {
+    const typedefRule: Record<string, boolean> = {};
+    const functionReturnRule: Record<string, boolean> = {};
+    const moduleBoundaryRule: Record<string, boolean> = {};
+
+    const originalArguments = new Set(tslintRule.ruleArguments);
+
+    const argumentEquivalents = {
+        parameter: "parameter",
+        "arrow-parameter": "arrowParameter",
+        "property-declaration": "propertyDeclaration",
+        "variable-declaration": "variableDeclaration",
+        "variable-declaration-ignore-function": "variableDeclarationIgnoreFunction",
+        "member-variable-declaration": "memberVariableDeclaration",
+        "object-destructuring": "objectDestructuring",
+        "array-destructuring": "arrayDestructuring",
+    };
+
+    for (const [tslintArgument, eslintArgument] of Object.entries(argumentEquivalents)) {
+        if (originalArguments.has(tslintArgument)) typedefRule[eslintArgument] = true;
+    }
+
+    const checksFunctionCallSignture =
+        originalArguments.has("arrow-call-signature") || originalArguments.has("call-signature");
+    if (checksFunctionCallSignture) {
+        functionReturnRule.allowExpressions = false;
+        functionReturnRule.allowTypedFunctionExpressions = false;
+        functionReturnRule.allowHigherOrderFunctions = false;
+        functionReturnRule.allowDirectConstAssertionInArrowFunctions = true;
+        functionReturnRule.allowConciseArrowFunctionExpressionsStartingWithVoid = true;
+
+        moduleBoundaryRule.allowArgumentsExplicitlyTypedAsAny = true;
+        moduleBoundaryRule.allowDirectConstAssertionInArrowFunctions = true;
+        moduleBoundaryRule.allowHigherOrderFunctions = false;
+        moduleBoundaryRule.allowTypedFunctionExpressions = false;
+    }
+
+    return {
+        ...(checksFunctionCallSignture && {
+            notices: [
+                "ESLint does not differentiate between the call signatures of arrow and non-arrow functions. Both will be checked",
+            ],
+        }),
+        rules: [
+            {
+                ...(Object.keys(typedefRule).length !== 0 && {
+                    ruleArguments: [typedefRule],
+                }),
+                ruleName: "@typescript-eslint/typedef",
+            },
+            {
+                ...(Object.keys(functionReturnRule).length !== 0 && {
+                    ruleArguments: [functionReturnRule],
+                }),
+                ruleName: "@typescript-eslint/explicit-function-return-type",
+            },
+            {
+                ...(Object.keys(moduleBoundaryRule).length !== 0 && {
+                    ruleArguments: [moduleBoundaryRule],
+                }),
+                ruleName: "@typescript-eslint/explicit-module-boundary-types",
+            },
+        ],
+    };
+};


Test patch:
diff --git a/src/converters/lintConfigs/rules/ruleConverters/tests/typedef.test.ts b/src/converters/lintConfigs/rules/ruleConverters/tests/typedef.test.ts
new file mode 100644
index 0000000..e13d9b9
--- /dev/null
+++ b/src/converters/lintConfigs/rules/ruleConverters/tests/typedef.test.ts
@@ -0,0 +1,177 @@
+import { describe, expect, test } from "@jest/globals";
+
+import { convertTypedef } from "../typedef";
+
+describe("convertTypedef", () => {
+    test("conversion without arguments", () => {
+        const result = convertTypedef({
+            ruleArguments: [],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleName: "@typescript-eslint/typedef",
+                },
+                {
+                    ruleName: "@typescript-eslint/explicit-function-return-type",
+                },
+                {
+                    ruleName: "@typescript-eslint/explicit-module-boundary-types",
+                },
+            ],
+        });
+    });
+
+    test("conversion with a few arguments", () => {
+        const result = convertTypedef({
+            ruleArguments: [
+                "parameter",
+                "variable-declaration-ignore-function",
+                "array-destructuring",
+            ],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleArguments: [
+                        {
+                            parameter: true,
+                            variableDeclarationIgnoreFunction: true,
+                            arrayDestructuring: true,
+                        },
+                    ],
+                    ruleName: "@typescript-eslint/typedef",
+                },
+                {
+                    ruleName: "@typescript-eslint/explicit-function-return-type",
+                },
+                {
+                    ruleName: "@typescript-eslint/explicit-module-boundary-types",
+                },
+            ],
+        });
+    });
+
+    test("conversion with all arguments", () => {
+        const result = convertTypedef({
+            ruleArguments: [
+                "parameter",
+                "arrow-parameter",
+                "property-declaration",
+                "variable-declaration",
+                "variable-declaration-ignore-function",
+                "member-variable-declaration",
+                "object-destructuring",
+                "array-destructuring",
+            ],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleArguments: [
+                        {
+                            parameter: true,
+                            arrowParameter: true,
+                            propertyDeclaration: true,
+                            variableDeclaration: true,
+                            variableDeclarationIgnoreFunction: true,
+                            memberVariableDeclaration: true,
+                            objectDestructuring: true,
+                            arrayDestructuring: true,
+                        },
+                    ],
+                    ruleName: "@typescript-eslint/typedef",
+                },
+                {
+                    ruleName: "@typescript-eslint/explicit-function-return-type",
+                },
+                {
+                    ruleName: "@typescript-eslint/explicit-module-boundary-types",
+                },
+            ],
+        });
+    });
+
+    test("conversion with call-signature", () => {
+        const result = convertTypedef({
+            ruleArguments: ["call-signature"],
+        });
+
+        expect(result).toEqual({
+            notices: [
+                "ESLint does not differentiate between the call signatures of arrow and non-arrow functions. Both will be checked",
+            ],
+            rules: [
+                {
+                    ruleName: "@typescript-eslint/typedef",
+                },
+                {
+                    ruleArguments: [
+                        {
+                            allowExpressions: false,
+                            allowTypedFunctionExpressions: false,
+                            allowHigherOrderFunctions: false,
+                            allowDirectConstAssertionInArrowFunctions: true,
+                            allowConciseArrowFunctionExpressionsStartingWithVoid: true,
+                        },
+                    ],
+                    ruleName: "@typescript-eslint/explicit-function-return-type",
+                },
+                {
+                    ruleArguments: [
+                        {
+                            allowArgumentsExplicitlyTypedAsAny: true,
+                            allowDirectConstAssertionInArrowFunctions: true,
+                            allowHigherOrderFunctions: false,
+                            allowTypedFunctionExpressions: false,
+                        },
+                    ],
+                    ruleName: "@typescript-eslint/explicit-module-boundary-types",
+                },
+            ],
+        });
+    });
+
+    test("conversion with arrow-call-signature", () => {
+        const result = convertTypedef({
+            ruleArguments: ["arrow-call-signature"],
+        });
+
+        expect(result).toEqual({
+            notices: [
+                "ESLint does not differentiate between the call signatures of arrow and non-arrow functions. Both will be checked",
+            ],
+            rules: [
+                {
+                    ruleName: "@typescript-eslint/typedef",
+                },
+                {
+                    ruleArguments: [
+                        {
+                            allowExpressions: false,
+                            allowTypedFunctionExpressions: false,
+                            allowHigherOrderFunctions: false,
+                            allowDirectConstAssertionInArrowFunctions: true,
+                            allowConciseArrowFunctionExpressionsStartingWithVoid: true,
+                        },
+                    ],
+                    ruleName: "@typescript-eslint/explicit-function-return-type",
+                },
+                {
+                    ruleArguments: [
+                        {
+                            allowArgumentsExplicitlyTypedAsAny: true,
+                            allowDirectConstAssertionInArrowFunctions: true,
+                            allowHigherOrderFunctions: false,
+                            allowTypedFunctionExpressions: false,
+                        },
+                    ],
+                    ruleName: "@typescript-eslint/explicit-module-boundary-types",
+                },
+            ],
+        });
+    });
+});