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

Issue:
Missing Merger:  @typescript-eslint/member-delimiter-style
### 💥 Missing Merger

-   `tslint-to-eslint-config` version: 0.2.8
-   ESLint version: 6.5.1

#### CLI Output

![image](https://user-images.githubusercontent.com/10083505/67468140-aa836600-f652-11e9-9e27-6a3760f2ec3c.png)

#### File Output

```
Error: multiple output @typescript-eslint/member-delimiter-style ESLint rule options were generated, but tslint-to-eslint-config doesn't have "merger" logic to deal with this.
Please file an issue at https://github.com/typescript-eslint/tslint-to-eslint-config/issues/new?template=missing_merger.md 🙏comment-format does not yet have an ESLint equivalent.
jsdoc-format does not yet have an ESLint equivalent.
jsx-key does not yet have an ESLint equivalent.
jsx-no-bind does not yet have an ESLint equivalent.
jsx-no-string-ref does not yet have an ESLint equivalent.
jsx-self-close does not yet have an ESLint equivalent.
no-reference-import does not yet have an ESLint equivalent.
prettier does not yet have an ESLint equivalent.
react-hooks-nesting does not yet have an ESLint equivalent.
readonly-array does not yet have an ESLint equivalent.
```

#### Reproduction

https://gist.github.com/evless/e395faa19b9f43098738ec25e36ee6f0


Pull request:
feat: add missing merger [member-delimiter-style] #254
<!--
👋 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 #254 
-   [x] That issue was marked as [`status: accepting prs`](https://github.com/typescript-eslint/tslint-to-eslint-config/labels/status%3A%20accepting%20prs)

## Overview

Adding missing merger `@typescript-eslint/member-delimiter-style`.

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/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/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/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/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,
+                },
+            },
+        ]);
+    });
+});