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

Issue:
Missing converter: no-unused-expression
### 💥 Missing Converter

-   `tslint-to-eslint-config` version: 1.2.0
-   `typescript-eslint` version: 2.3.2

#### TSLint Rule Name

`no-unused-expression`


Pull request description:
Added no-unused-expression converter
<!--
👋 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 #177 
-   [X] That issue was marked as [`status: accepting prs`](https://github.com/typescript-eslint/tslint-to-eslint-config/labels/status%3A%20accepting%20prs)

## Overview

<!-- Brief description of what is changed and how the code change does that. -->

Added converter for  TSLint rule "no-unused-expression" and unit tests


Patch:
diff --git a/src/rules/converters.ts b/src/rules/converters.ts
index df51c92..d7846f6 100644
--- a/src/rules/converters.ts
+++ b/src/rules/converters.ts
@@ -88,6 +88,7 @@ import { convertNoUnnecessaryQualifier } from "./converters/no-unnecessary-quali
 import { convertNoUnnecessarySemicolons } from "./converters/no-unnecessary-semicolons";
 import { convertNoUnnecessaryTypeAssertion } from "./converters/no-unnecessary-type-assertion";
 import { convertNoUnsafeFinally } from "./converters/no-unsafe-finally";
+import { convertNoUnusedExpression } from "./converters/no-unused-expression";
 import { convertNoUseBeforeDeclare } from "./converters/no-use-before-declare";
 import { convertNoVarKeyword } from "./converters/no-var-keyword";
 import { convertNoVarRequires } from "./converters/no-var-requires";
@@ -215,6 +216,7 @@ export const converters = new Map([
     ["no-unnecessary-semicolons", convertNoUnnecessarySemicolons],
     ["no-unnecessary-type-assertion", convertNoUnnecessaryTypeAssertion],
     ["no-unsafe-finally", convertNoUnsafeFinally],
+    ["no-unused-expression", convertNoUnusedExpression],
     ["no-use-before-declare", convertNoUseBeforeDeclare],
     ["no-var-keyword", convertNoVarKeyword],
     ["no-var-requires", convertNoVarRequires],
@@ -257,7 +259,6 @@ export const converters = new Map([
     // ["ban", convertBan], // no-restricted-properties
     // ["import-blacklist", convertImportBlacklist], // no-restricted-imports
     // ["no-duplicate-variable", convertNoDuplicateVariable], // no-redeclare
-    // ["no-unused-expression", convertNoUnusedExpression], // no-unused-expressions
     // ["no-void-expression", convertNoVoidExpression], // (no exact equivalent)
     // ["quotemark", convertQuotemark], // quotes
     // ["triple-equals", convertTripleEquals], // eqeqeq
diff --git a/src/rules/converters/no-unused-expression.ts b/src/rules/converters/no-unused-expression.ts
new file mode 100644
index 0000000..a1142b5
--- /dev/null
+++ b/src/rules/converters/no-unused-expression.ts
@@ -0,0 +1,46 @@
+import { RuleConverter } from "../converter";
+
+export const convertNoUnusedExpression: RuleConverter = tslintRule => {
+    return {
+        rules: [
+            {
+                ruleName: "no-unused-expressions",
+                ...collectNoticesAndArguments(tslintRule.ruleArguments),
+            },
+        ],
+    };
+};
+
+const collectNoticesAndArguments = (tsLintRuleArguments: any[]) => {
+    const noAllowNewNotice = `The TSLint optional config "allow-new" is the default ESLint behavior and will no longer be ignored.`;
+
+    if (tsLintRuleArguments.length === 0) {
+        return {
+            notices: [noAllowNewNotice],
+        };
+    }
+
+    const notices = [];
+    const ruleArguments: any[] = [];
+
+    if (tsLintRuleArguments.includes("allow-tagged-template")) {
+        ruleArguments.push({ allowTaggedTemplates: true });
+    }
+
+    if (tsLintRuleArguments.includes("allow-fast-null-checks")) {
+        ruleArguments.push({ allowShortCircuit: true });
+    }
+
+    if (!tsLintRuleArguments.includes("allow-new")) {
+        notices.push(noAllowNewNotice);
+    }
+
+    return {
+        ...(notices.length > 0 && { notices }),
+        ...(ruleArguments.length > 0 && {
+            ruleArguments: [
+                ruleArguments.reduce((value, current) => Object.assign(value, current), {}),
+            ],
+        }),
+    };
+};


Test patch:
diff --git a/src/rules/converters/tests/no-unused-expression.test.ts b/src/rules/converters/tests/no-unused-expression.test.ts
new file mode 100644
index 0000000..cd31fbe
--- /dev/null
+++ b/src/rules/converters/tests/no-unused-expression.test.ts
@@ -0,0 +1,83 @@
+import { convertNoUnusedExpression } from "../no-unused-expression";
+
+describe(convertNoUnusedExpression, () => {
+    test("conversion without arguments", () => {
+        const result = convertNoUnusedExpression({
+            ruleArguments: [],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleName: "no-unused-expressions",
+                    notices: [
+                        `The TSLint optional config "allow-new" is the default ESLint behavior and will no longer be ignored.`,
+                    ],
+                },
+            ],
+        });
+    });
+
+    test("conversion without allow-new argument", () => {
+        const result = convertNoUnusedExpression({
+            ruleArguments: ["allow-fast-null-checks"],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleName: "no-unused-expressions",
+                    ruleArguments: [{ allowShortCircuit: true }],
+                    notices: [
+                        `The TSLint optional config "allow-new" is the default ESLint behavior and will no longer be ignored.`,
+                    ],
+                },
+            ],
+        });
+    });
+
+    test("conversion with allow-tagged-template argument", () => {
+        const result = convertNoUnusedExpression({
+            ruleArguments: ["allow-new", "allow-tagged-template"],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleArguments: [{ allowTaggedTemplates: true }],
+                    ruleName: "no-unused-expressions",
+                },
+            ],
+        });
+    });
+
+    test("conversion with allow-fast-null-checks argument", () => {
+        const result = convertNoUnusedExpression({
+            ruleArguments: ["allow-new", "allow-fast-null-checks"],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleName: "no-unused-expressions",
+                    ruleArguments: [{ allowShortCircuit: true }],
+                },
+            ],
+        });
+    });
+
+    test("conversion with multiple arguments", () => {
+        const result = convertNoUnusedExpression({
+            ruleArguments: ["allow-new", "allow-tagged-template", "allow-fast-null-checks"],
+        });
+
+        expect(result).toEqual({
+            rules: [
+                {
+                    ruleName: "no-unused-expressions",
+                    ruleArguments: [{ allowTaggedTemplates: true, allowShortCircuit: true }],
+                },
+            ],
+        });
+    });
+});