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

Issue:
Incorrectly generated space-before-function-paren
### 🐛 Bug Report

-   `tslint-to-eslint-config` version: 0.2.5
-   ESLint version: 6.2.2
-   Node version: 12.6

#### Actual Behavior

The tool generates a

 ```json
        "space-before-function-paren": [
            "error",
            {
                "anonymous": "never",
                "asyncArrow": "always",
                "constructor": "never",
                "method": "never",
                "named": "never",
            },
        ],
```

rule which does not validate when Eslint is starting:

```
	Configuration for rule "space-before-function-paren" is invalid:
	Value {"anonymous":"never","asyncArrow":"always","constructor":"never","method":"never","named":"never"} should be equal to one of the allowed values.
	Value {"anonymous":"never","asyncArrow":"always","constructor":"never","method":"never","named":"never"} should NOT have additional properties.
	Value {"anonymous":"never","asyncArrow":"always","constructor":"never","method":"never","named":"never"} should match exactly one schema in oneOf.
```

#### Expected Behavior

The rule is correctly generated according to [the spec](https://eslint.org/docs/rules/space-before-function-paren#options). It seems `method` and `constructor` shouldn't be there.

Pull request:
Generating `space-before-function-paren` (#147)
<!--
👋 Hi, thanks for sending a PR to tslint-to-eslint-config! 💖
Please fill out all fields below to ensure your PR is reviewed quickly.
-->

## PR Checklist

-   [x] Addresses an existing issue: fixes #147 
-   [x] That issue was marked as [`status: accepting prs`](https://github.com/typescript-eslint/tslint-to-eslint-config/labels/status%3A%20accepting%20prs)

## Overview

- Added filtering of TSLint [rules arguments](https://palantir.github.io/tslint/rules/space-before-function-paren/) to allow only some of them, which are available in [ESLint](https://eslint.org/docs/rules/space-before-function-paren#options).
- Added test.

Patch:
diff --git a/src/rules/converters.ts b/src/rules/converters.ts
index 4a4ce1a..69aa786 100644
--- a/src/rules/converters.ts
+++ b/src/rules/converters.ts
@@ -74,6 +74,7 @@ import { convertNoObjectLiteralTypeAssertion } from "./converters/no-object-lite
 import { convertNoOctalLiteral } from "./converters/no-octal-literal";
 import { convertNoParameterProperties } from "./converters/no-parameter-properties";
 import { convertNoParameterReassignment } from "./converters/no-parameter-reassignment";
+import { convertNoRedundantJsdoc } from "./converters/no-redundant-jsdoc";
 import { convertNoReference } from "./converters/no-reference";
 import { convertNoRegexSpaces } from "./converters/no-regex-spaces";
 import { convertNoRequireImports } from "./converters/no-require-imports";
@@ -210,6 +211,7 @@ export const converters = new Map([
     ["no-octal-literal", convertNoOctalLiteral],
     ["no-parameter-properties", convertNoParameterProperties],
     ["no-parameter-reassignment", convertNoParameterReassignment],
+    ["no-redundant-jsdoc", convertNoRedundantJsdoc],
     ["no-reference", convertNoReference],
     ["no-regex-spaces", convertNoRegexSpaces],
     ["no-require-imports", convertNoRequireImports],
diff --git a/src/rules/converters/newline-before-return.ts b/src/rules/converters/newline-before-return.ts
index 3e6916a..102362e 100644
--- a/src/rules/converters/newline-before-return.ts
+++ b/src/rules/converters/newline-before-return.ts
@@ -6,7 +6,6 @@ export const convertNewlineBeforeReturn: RuleConverter = () => {
             {
                 ruleName: "padding-line-between-statements",
                 ruleArguments: [
-                    "error",
                     {
                         blankLine: "always",
                         prev: "*",
diff --git a/src/rules/converters/no-redundant-jsdoc.ts b/src/rules/converters/no-redundant-jsdoc.ts
new file mode 100644
index 0000000..7318520
--- /dev/null
+++ b/src/rules/converters/no-redundant-jsdoc.ts
@@ -0,0 +1,10 @@
+import { RuleConverter } from "../converter";
+
+export const convertNoRedundantJsdoc: RuleConverter = () => ({
+    rules: [
+        {
+            ruleName: "jsdoc/no-types",
+        },
+    ],
+    plugins: ["eslint-plugin-jsdoc"],
+});
diff --git a/src/rules/converters/no-use-before-declare.ts b/src/rules/converters/no-use-before-declare.ts
index b83d1e4..b5c3727 100644
--- a/src/rules/converters/no-use-before-declare.ts
+++ b/src/rules/converters/no-use-before-declare.ts
@@ -4,7 +4,7 @@ export const convertNoUseBeforeDeclare: RuleConverter = () => {
     return {
         rules: [
             {
-                ruleName: "@typescript-eslint/no-use-before-declare",
+                ruleName: "@typescript-eslint/no-use-before-define",
             },
         ],
     };
diff --git a/src/rules/converters/semicolon.ts b/src/rules/converters/semicolon.ts
index ec75e7d..51d1ea5 100644
--- a/src/rules/converters/semicolon.ts
+++ b/src/rules/converters/semicolon.ts
@@ -24,7 +24,6 @@ export const convertSemicolon: RuleConverter = tslintRule => {
                 : [
                       {
                           ruleArguments: [
-                              "error",
                               {
                                   multiline: {
                                       delimiter: getMultilineDelimiter(tslintRule.ruleArguments[0]),
diff --git a/src/rules/converters/space-before-function-paren.ts b/src/rules/converters/space-before-function-paren.ts
index e29b056..916a598 100644
--- a/src/rules/converters/space-before-function-paren.ts
+++ b/src/rules/converters/space-before-function-paren.ts
@@ -1,11 +1,26 @@
 import { RuleConverter } from "../converter";
 
+const NOT_SUPPORTED_OPTIONS = ["constructor", "method"];
+
+function isExistedESLintOption(rule: string) {
+    return !NOT_SUPPORTED_OPTIONS.includes(rule);
+}
+
 export const convertSpaceBeforeFunctionParen: RuleConverter = tslintRule => {
+    const ruleArguments = tslintRule.ruleArguments.filter(isExistedESLintOption);
+    const notices = NOT_SUPPORTED_OPTIONS.reduce<string[]>((acc, option) => {
+        if (tslintRule.ruleArguments.includes(option)) {
+            acc.push(`Option "${option}" is not supported by ESLint.`);
+        }
+        return acc;
+    }, []);
+
     return {
         rules: [
             {
                 ...(tslintRule.ruleArguments.length !== 0 && {
-                    ruleArguments: tslintRule.ruleArguments,
+                    ruleArguments,
+                    ...(notices.length !== 0 && { notices }),
                 }),
                 ruleName: "space-before-function-paren",
             },
diff --git a/src/rules/mergers.ts b/src/rules/mergers.ts
index 446d686..3697234 100644
--- a/src/rules/mergers.ts
+++ b/src/rules/mergers.ts
@@ -1,5 +1,6 @@
 import { mergeBanTypes } from "./mergers/ban-types";
 import { mergeIndent } from "./mergers/indent";
+import { mergeNoMemberDelimiterStyle } from "./mergers/member-delimiter-style";
 import { mergeNoCaller } from "./mergers/no-caller";
 import { mergeNoEval } from "./mergers/no-eval";
 import { mergeNoUnnecessaryTypeAssertion } from "./mergers/no-unnecessary-type-assertion";
@@ -7,6 +8,7 @@ import { mergeNoUnnecessaryTypeAssertion } from "./mergers/no-unnecessary-type-a
 export const mergers = new Map([
     ["@typescript-eslint/ban-types", mergeBanTypes],
     ["@typescript-eslint/indent", mergeIndent],
+    ["@typescript-eslint/member-delimiter-style", mergeNoMemberDelimiterStyle],
     ["@typescript-eslint/no-unnecessary-type-assertion", mergeNoUnnecessaryTypeAssertion],
     ["no-caller", mergeNoCaller],
     ["no-eval", mergeNoEval],
diff --git a/src/rules/mergers/member-delimiter-style.ts b/src/rules/mergers/member-delimiter-style.ts
new file mode 100644
index 0000000..52cfa1e
--- /dev/null
+++ b/src/rules/mergers/member-delimiter-style.ts
@@ -0,0 +1,21 @@
+import { RuleMerger } from "../merger";
+
+export const mergeNoMemberDelimiterStyle: RuleMerger = (existingOptions, newOptions) => {
+    if (existingOptions === undefined && newOptions === undefined) {
+        return [];
+    }
+
+    return [merge((existingOptions || [])[0] || {}, (newOptions || [])[0] || {})];
+};
+
+const merge = (...objs: Record<string, any>[]) =>
+    [...objs].reduce(
+        (acc, obj) => ({
+            ...acc,
+            ...Object.keys(obj).reduce((_, k) => {
+                acc[k] = obj[k];
+                return acc;
+            }, {}),
+        }),
+        {},
+    );


Test patch:
diff --git a/src/rules/convertRuleSeverity.test.ts b/src/rules/convertRuleSeverity.test.ts
index c72b200..2297e7b 100644
--- a/src/rules/convertRuleSeverity.test.ts
+++ b/src/rules/convertRuleSeverity.test.ts
@@ -47,7 +47,7 @@ describe("convertRawESLintRuleSeverity", () => {
         expect(converted).toEqual("off");
     });
 
-    it("returns off when the severity is 2", () => {
+    it("returns warn when the severity is 1", () => {
         // Arrange
         const rawSeverity = 1;
 
@@ -58,7 +58,7 @@ describe("convertRawESLintRuleSeverity", () => {
         expect(converted).toEqual("warn");
     });
 
-    it("returns off when the severity is 3", () => {
+    it("returns error when the severity is 2", () => {
         // Arrange
         const rawSeverity = 2;
 
diff --git a/src/rules/converters/tests/newline-before-return.test.ts b/src/rules/converters/tests/newline-before-return.test.ts
index 97f8dc7..d216ce6 100644
--- a/src/rules/converters/tests/newline-before-return.test.ts
+++ b/src/rules/converters/tests/newline-before-return.test.ts
@@ -11,7 +11,6 @@ describe(convertNewlineBeforeReturn, () => {
                 {
                     ruleName: "padding-line-between-statements",
                     ruleArguments: [
-                        "error",
                         {
                             blankLine: "always",
                             next: "return",
diff --git a/src/rules/converters/tests/no-redundant-jsdoc.test.ts b/src/rules/converters/tests/no-redundant-jsdoc.test.ts
new file mode 100644
index 0000000..7d060fc
--- /dev/null
+++ b/src/rules/converters/tests/no-redundant-jsdoc.test.ts
@@ -0,0 +1,18 @@
+import { convertNoRedundantJsdoc } from "../no-redundant-jsdoc";
+
+describe(convertNoRedundantJsdoc, () => {
+    test("conversion without arguments", () => {
+        const result = convertNoRedundantJsdoc({
+            ruleArguments: [],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleName: "jsdoc/no-types",
+                },
+            ],
+            plugins: ["eslint-plugin-jsdoc"],
+        });
+    });
+});
diff --git a/src/rules/converters/tests/no-use-before-declare.test.ts b/src/rules/converters/tests/no-use-before-declare.test.ts
index 1e4b663..0631a48 100644
--- a/src/rules/converters/tests/no-use-before-declare.test.ts
+++ b/src/rules/converters/tests/no-use-before-declare.test.ts
@@ -9,7 +9,7 @@ describe(convertNoUseBeforeDeclare, () => {
         expect(result).toEqual({
             rules: [
                 {
-                    ruleName: "@typescript-eslint/no-use-before-declare",
+                    ruleName: "@typescript-eslint/no-use-before-define",
                 },
             ],
         });
diff --git a/src/rules/converters/tests/semicolon.test.ts b/src/rules/converters/tests/semicolon.test.ts
index 55c96ff..f7cb30a 100644
--- a/src/rules/converters/tests/semicolon.test.ts
+++ b/src/rules/converters/tests/semicolon.test.ts
@@ -14,7 +14,6 @@ describe(convertSemicolon, () => {
                 },
                 {
                     ruleArguments: [
-                        "error",
                         {
                             multiline: {
                                 delimiter: "semi",
@@ -45,7 +44,6 @@ describe(convertSemicolon, () => {
                 },
                 {
                     ruleArguments: [
-                        "error",
                         {
                             multiline: {
                                 delimiter: "none",
@@ -77,7 +75,6 @@ describe(convertSemicolon, () => {
                 {
                     ruleName: "@typescript-eslint/member-delimiter-style",
                     ruleArguments: [
-                        "error",
                         {
                             multiline: {
                                 delimiter: "semi",
@@ -111,7 +108,6 @@ describe(convertSemicolon, () => {
                 {
                     ruleName: "@typescript-eslint/member-delimiter-style",
                     ruleArguments: [
-                        "error",
                         {
                             multiline: {
                                 delimiter: "none",
diff --git a/src/rules/converters/tests/space-before-function-paren.test.ts b/src/rules/converters/tests/space-before-function-paren.test.ts
index bb7bd78..b83285f 100644
--- a/src/rules/converters/tests/space-before-function-paren.test.ts
+++ b/src/rules/converters/tests/space-before-function-paren.test.ts
@@ -29,4 +29,42 @@ describe(convertSpaceBeforeFunctionParen, () => {
             ],
         });
     });
+
+    test("conversion with all existing arguments", () => {
+        const result = convertSpaceBeforeFunctionParen({
+            ruleArguments: ["anonymous", "named", "asyncArrow", "method", "constructor"],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    notices: [
+                        'Option "constructor" is not supported by ESLint.',
+                        'Option "method" is not supported by ESLint.',
+                    ],
+                    ruleArguments: ["anonymous", "named", "asyncArrow"],
+                    ruleName: "space-before-function-paren",
+                },
+            ],
+        });
+    });
+
+    test('conversion with not supported options ["method", "constructor"]', () => {
+        const result = convertSpaceBeforeFunctionParen({
+            ruleArguments: ["method", "constructor"],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    notices: [
+                        'Option "constructor" is not supported by ESLint.',
+                        'Option "method" is not supported by ESLint.',
+                    ],
+                    ruleArguments: [],
+                    ruleName: "space-before-function-paren",
+                },
+            ],
+        });
+    });
 });
diff --git a/src/rules/mergers/tests/member-delimiter-style.test.ts b/src/rules/mergers/tests/member-delimiter-style.test.ts
new file mode 100644
index 0000000..17ad634
--- /dev/null
+++ b/src/rules/mergers/tests/member-delimiter-style.test.ts
@@ -0,0 +1,98 @@
+import { mergeNoMemberDelimiterStyle } from "../member-delimiter-style";
+
+describe(mergeNoMemberDelimiterStyle, () => {
+    test("neither options existing", () => {
+        const result = mergeNoMemberDelimiterStyle(undefined, undefined);
+
+        expect(result).toEqual([]);
+    });
+
+    test("new object config existing", () => {
+        const result = mergeNoMemberDelimiterStyle(undefined, [
+            {
+                multiline: {
+                    delimiter: "semi",
+                    requireLast: true,
+                },
+                singleline: {
+                    delimiter: "semi",
+                    requireLast: false,
+                },
+            },
+        ]);
+
+        expect(result).toEqual([
+            {
+                multiline: {
+                    delimiter: "semi",
+                    requireLast: true,
+                },
+                singleline: {
+                    delimiter: "semi",
+                    requireLast: false,
+                },
+            },
+        ]);
+    });
+
+    test("original object config existing", () => {
+        const result = mergeNoMemberDelimiterStyle(
+            [
+                {
+                    multiline: {
+                        delimiter: "semi",
+                        requireLast: true,
+                    },
+                },
+            ],
+            undefined,
+        );
+
+        expect(result).toEqual([
+            {
+                multiline: {
+                    delimiter: "semi",
+                    requireLast: true,
+                },
+            },
+        ]);
+    });
+
+    test("both object config existing", () => {
+        const result = mergeNoMemberDelimiterStyle(
+            [
+                {
+                    singleline: {
+                        delimiter: "semi",
+                        requireLast: false,
+                    },
+                },
+            ],
+            [
+                {
+                    singleline: {
+                        delimiter: "semi",
+                        requireLast: false,
+                    },
+                    multiline: {
+                        delimiter: "semi",
+                        requireLast: true,
+                    },
+                },
+            ],
+        );
+
+        expect(result).toEqual([
+            {
+                multiline: {
+                    delimiter: "semi",
+                    requireLast: true,
+                },
+                singleline: {
+                    delimiter: "semi",
+                    requireLast: false,
+                },
+            },
+        ]);
+    });
+});