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

Issue:
Switch detailed rule differences to info (file) output
### 🚀 Feature Request

Rule behavior changes are pretty verbose in a lot of configurations. They're the only category of verbose, many-line output with all output written to stdout. Others log a small summary to stdout and put details in the log file.

#### Existing Behavior

As of #246, typical CLI output might look like this:

```
λ tslint-to-eslint-config --comments *.ts
✨ 90 rules replaced with their ESLint equivalents. ✨

❗ 7 ESLint rules behave differently from their TSLint counterparts ❗
  * camelcase:
    - Leading undescores in variable names will now be ignored.
    - ESLint's camel-case rule does not allow pascal or snake case variable names. Those cases are reserved for class names and static methods.
  * no-underscore-dangle:
    - Leading and trailing underscores (_) on identifiers will now be ignored.
  * space-before-function-paren:
    - Option "method" is not supported by ESLint.
    - Option "constructor" is not supported by ESLint.
  * no-console:
    - Custom console methods, if they exist, will no longer be allowed.
  * import/no-extraneous-dependencies:
    - ESLint does not support whitelisting modules
  * no-invalid-this:
    - Functions in methods will no longer be ignored.
  * no-unused-expressions:
    - The TSLint optional config "allow-new" is the default ESLint behavior and will no longer be ignored.

❌ 1 error thrown. ❌
  Check ./tslint-to-eslint-config.log for details.
️
❓ 1 rule does not yet have an ESLint equivalent ❓
  See generated log file; defaulting to eslint-plugin-tslint for it.

⚡ 4 packages are required for new ESLint rules. ⚡
  eslint-plugin-import
  import
  eslint-plugin-jsdoc
  prefer-arrow

♻ 2 files of TSLint comment directives converted to ESLint. ♻

✅ All is well! ✅
```

#### Change Proposal

Let's print the typical _"see *.log for details"_ file instead.

Pull request:
Standardized outputs: CLI summaries, log details
## PR Checklist

-   [x] Addresses an existing issue: fixes #404
-   [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 new output is now like:

![Screenshot of the trimmed CLI output (read below)](https://user-images.githubusercontent.com/3335181/80294702-39c02200-8739-11ea-97f8-222aef6287f8.png)

```
✨ 90 rules replaced with their ESLint equivalents. ✨

❗ 10 ESLint rules behave differently from their TSLint counterparts ❗
  Check ./tslint-to-eslint-config.log for details.

❌ 1 error thrown. ❌
  Check ./tslint-to-eslint-config.log for details.
️
❓ 1 rule is not known by tslint-to-eslint-config to have an ESLint equivalent. ❓
  The "@typescript-eslint/tslint/config" section of ./.eslintrc.js configures eslint-plugin-tslint to run it in TSLint within ESLint.
  Check ./tslint-to-eslint-config.log for details.

⚡ 6 packages are required for running with ESLint. ⚡
  npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-plugin-import eslint-plugin-jsdoc eslint-plugin-prefer-arrow --save-dev
️
❓ 1 editor setting is not known by tslint-to-eslint-config to have an ESLint equivalent. ❓
  Check ./tslint-to-eslint-config.log for details.

✅ All is well! ✅
```

...with the file:

```
10 ESLint rules behave differently from their TSLint counterparts:
  * camelcase:
    - Leading undescores in variable names will now be ignored.
    - ESLint's camel-case rule does not allow pascal or snake case variable names. Those cases are reserved for class names and static methods.
  * no-underscore-dangle:
    - Leading and trailing underscores (_) on identifiers will now be ignored.
  * space-before-function-paren:
    - Option "method" is not supported by ESLint.
    - Option "constructor" is not supported by ESLint.
  * no-console:
    - Custom console methods, if they exist, will no longer be allowed.
  * import/no-extraneous-dependencies:
    - ESLint does not support whitelisting modules
  * no-invalid-this:
    - Functions in methods will no longer be ignored.
  * no-unused-expressions:
    - The TSLint optional config "allow-new" is the default ESLint behavior and will no longer be ignored.
  * prefer-arrow/prefer-arrow-functions:
    - ESLint does not support allowing standalone function declarations.
    - ESLint does not support allowing named functions defined with the function keyword.
  * eqeqeq:
    - Option "smart" allows for comparing two literal values, evaluating the value of typeof and null comparisons.
  * no-redeclare:
    - ESLint does not support check-parameters.

Error: multiple output @typescript-eslint/triple-slash-reference 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. Thanks!

1 rule is not known by tslint-to-eslint-config to have an ESLint equivalent:
  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint's "prefer-conditional-expression".

1 editor setting is not known by tslint-to-eslint-config to have an ESLint equivalent:
  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint's "editor.tabSize".
```

Patch:
diff --git a/src/cli/runCli.ts b/src/cli/runCli.ts
index 2d6a85e..a1a3538 100644
--- a/src/cli/runCli.ts
+++ b/src/cli/runCli.ts
@@ -45,7 +45,7 @@ export const runCli = async (
         }
     }
 
-    dependencies.logger.stdout.write(chalk.greenBright("✅ All is well! ✅\n"));
+    dependencies.logger.stdout.write(chalk.greenBright(`${EOL}✅ All is well! ✅\n`));
     return ResultStatus.Succeeded;
 };
 
diff --git a/src/conversion/convertConfig.ts b/src/conversion/convertConfig.ts
index 2305bad..67e8b93 100644
--- a/src/conversion/convertConfig.ts
+++ b/src/conversion/convertConfig.ts
@@ -57,7 +57,7 @@ export const convertConfig = async (
     }
 
     // 5. A summary of the results is printed to the user's console
-    await dependencies.reportConversionResults(simplifiedConfiguration);
+    await dependencies.reportConversionResults(settings.config, simplifiedConfiguration);
 
     return {
         status: ResultStatus.Succeeded,
diff --git a/src/errors/conversionError.ts b/src/errors/conversionError.ts
index c2766c8..1482a5e 100644
--- a/src/errors/conversionError.ts
+++ b/src/errors/conversionError.ts
@@ -11,7 +11,7 @@ export class ConversionError implements ErrorSummary {
         return new ConversionError(
             [
                 `Error: multiple output ${eslintRule} 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 🙏`,
+                `Please file an issue at https://github.com/typescript-eslint/tslint-to-eslint-config/issues/new?template=missing_merger.md. Thanks!`,
             ].join(EOL),
         );
     }
diff --git a/src/reporting/reportConversionResults.ts b/src/reporting/reportConversionResults.ts
index b68b259..f3cc475 100644
--- a/src/reporting/reportConversionResults.ts
+++ b/src/reporting/reportConversionResults.ts
@@ -20,6 +20,7 @@ export type ReportConversionResultsDependencies = {
 
 export const reportConversionResults = async (
     dependencies: ReportConversionResultsDependencies,
+    outputPath: string,
     ruleConversionResults: RuleConversionResults,
 ) => {
     const packageManager = await dependencies.choosePackageManager();
@@ -36,14 +37,13 @@ export const reportConversionResults = async (
     if (ruleConversionResults.missing.length !== 0) {
         logMissingConversionTarget(
             "rule",
-            (setting: TSLintRuleOptions) =>
-                `tslint-to-eslint-config does not know the ESLint equivalent for TSLint's "${setting.ruleName}"${EOL}`,
+            (setting: TSLintRuleOptions) => setting.ruleName,
             ruleConversionResults.missing,
             dependencies.logger,
             [
-                ruleConversionResults.missing.length === 1
-                    ? "defaulting to eslint-plugin-tslint for it."
-                    : "defaulting to eslint-plugin-tslint for these rules.",
+                `The "@typescript-eslint/tslint/config" section of ${outputPath} configures eslint-plugin-tslint to run ${
+                    ruleConversionResults.missing.length === 1 ? "it" : "them"
+                } in TSLint within ESLint.`,
             ],
         );
     }
@@ -61,29 +61,28 @@ const logNotices = (converted: Map<string, ESLintRuleOptions>, logger: Logger) =
         (ruleOptions) => ruleOptions.notices && ruleOptions.notices.length >= 1,
     ) as RuleWithNotices[];
 
-    if (rulesWithNotices.length !== 0) {
-        logger.stdout.write(chalk.yellowBright(`${EOL}❗ ${rulesWithNotices.length} ESLint`));
+    if (rulesWithNotices.length === 0) {
+        return;
+    }
 
-        if (rulesWithNotices.length === 1) {
-            logger.stdout.write(
-                chalk.yellowBright(
-                    ` rule behaves differently from its TSLint counterpart ❗${EOL}`,
-                ),
-            );
-        } else {
-            logger.stdout.write(
-                chalk.yellowBright(
-                    ` rules behave differently from their TSLint counterparts ❗${EOL}`,
-                ),
-            );
-        }
+    const behavior =
+        rulesWithNotices.length === 1
+            ? " behaves differently from its TSLint counterpart"
+            : "s behave differently from their TSLint counterparts";
 
-        for (const rule of rulesWithNotices) {
-            logger.stdout.write(chalk.yellow(`  * ${rule.ruleName}:${EOL}`));
+    logger.stdout.write(
+        chalk.blueBright(`${EOL}❗ ${rulesWithNotices.length} ESLint rule${behavior} ❗${EOL}`),
+    );
+    logger.stdout.write(chalk.blue(`  Check ${logger.debugFileName} for details.${EOL}`));
+    logger.info.write(`${rulesWithNotices.length} ESLint rule${behavior}:${EOL}`);
 
-            for (const notice of rule.notices) {
-                logger.stdout.write(chalk.yellow(`    - ${notice}${EOL}`));
-            }
+    for (const rule of rulesWithNotices) {
+        logger.info.write(`  * ${rule.ruleName}:${EOL}`);
+
+        for (const notice of rule.notices) {
+            logger.info.write(`    - ${notice}${EOL}`);
         }
     }
+
+    logger.info.write(EOL);
 };
diff --git a/src/reporting/reportEditorSettingConversionResults.ts b/src/reporting/reportEditorSettingConversionResults.ts
index 85e06ac..38271d6 100644
--- a/src/reporting/reportEditorSettingConversionResults.ts
+++ b/src/reporting/reportEditorSettingConversionResults.ts
@@ -1,8 +1,5 @@
-import { EOL } from "os";
-
 import { Logger } from "../adapters/logger";
 import { EditorSettingConversionResults } from "../editorSettings/convertEditorSettings";
-import { EditorSetting } from "../editorSettings/types";
 import {
     logFailedConversions,
     logMissingConversionTarget,
@@ -30,13 +27,9 @@ export const reportEditorSettingConversionResults = (
     }
 
     if (editorSettingConversionResults.missing.length !== 0) {
-        const missingEditorSettingOutputMapping = (
-            editorSetting: Pick<EditorSetting, "editorSettingName">,
-        ) =>
-            `tslint-to-eslint-config does not know the ESLint equivalent for TSLint's "${editorSetting.editorSettingName}"${EOL}`;
         logMissingConversionTarget(
             "editor setting",
-            missingEditorSettingOutputMapping,
+            (editorSetting) => editorSetting.editorSettingName,
             editorSettingConversionResults.missing,
             dependencies.logger,
         );
diff --git a/src/reporting/reportOutputs.ts b/src/reporting/reportOutputs.ts
index 93e8c04..79a9a61 100644
--- a/src/reporting/reportOutputs.ts
+++ b/src/reporting/reportOutputs.ts
@@ -29,7 +29,7 @@ export const logFailedConversions = (failed: ErrorSummary[], logger: Logger) =>
     logger.stderr.write(chalk.red(" thrown."));
     logger.stderr.write(chalk.redBright(` ❌${EOL}`));
     logger.info.write(failed.map((failed) => failed.getSummary()).join("\n\n") + "\n\n");
-    logger.stderr.write(chalk.gray(`  Check ${logger.debugFileName} for details.${EOL}`));
+    logger.stderr.write(chalk.red(`  Check ${logger.debugFileName} for details.${EOL}`));
 };
 
 export const logMissingConversionTarget = <T>(
@@ -39,31 +39,33 @@ export const logMissingConversionTarget = <T>(
     logger: Logger,
     additionalWarnings: string[] = [],
 ) => {
+    const headline =
+        missing.length === 1
+            ? ` ${conversionTypeName} is not known by tslint-to-eslint-config to have an ESLint equivalent`
+            : ` ${conversionTypeName}s are not known by tslint-to-eslint-config to have ESLint equivalents`;
+
     logger.stdout.write(chalk.yellowBright(`️${EOL}❓ ${missing.length}`));
-    logger.stdout.write(
-        chalk.yellow(
-            missing.length === 1
-                ? ` ${conversionTypeName} does not yet have an ESLint equivalent`
-                : ` ${conversionTypeName}s do not yet have ESLint equivalents`,
-        ),
-    );
+    logger.stdout.write(chalk.yellow(`${headline}.`));
     logger.stdout.write(chalk.yellowBright(` ❓${EOL}`));
-    logger.stdout.write(chalk.yellow(`  See generated log file`));
 
-    if (additionalWarnings.length > 0) {
-        logger.stdout.write(chalk.yellow("; "));
-
-        for (const warning of additionalWarnings) {
-            logger.stdout.write(chalk.yellow(warning));
-        }
-    } else {
-        logger.stdout.write(chalk.yellow("."));
+    for (const warning of additionalWarnings) {
+        logger.stdout.write(chalk.yellow(`  ${warning}${EOL}`));
     }
 
+    logger.stdout.write(chalk.yellow(`  Check ${logger.debugFileName} for details.${EOL}`));
+
+    logger.info.write(`${missing.length}${headline}:${EOL}`);
     logger.info.write(
-        chalk.yellow(missing.map((conversion) => missingOutputMapping(conversion)).join("")),
+        missing
+            .map(
+                (conversion) =>
+                    `  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint's "${missingOutputMapping(
+                        conversion,
+                    )}".${EOL}`,
+            )
+            .join(""),
     );
-    logger.stdout.write(chalk.yellow(EOL));
+    logger.info.write(EOL);
 };
 
 export const logMissingPackages = (
@@ -83,5 +85,5 @@ export const logMissingPackages = (
     logger.stdout.write(chalk.cyanBright(" ⚡"));
     logger.stdout.write(`${EOL}  `);
     logger.stdout.write(chalk.cyan(installationMessages[packageManager](packageNames.join(" "))));
-    logger.stdout.write(EOL.repeat(2));
+    logger.stdout.write(EOL);
 };


Test patch:
diff --git a/src/errors/conversionError.test.ts b/src/errors/conversionError.test.ts
index 4a41dd7..c9981f2 100644
--- a/src/errors/conversionError.test.ts
+++ b/src/errors/conversionError.test.ts
@@ -33,7 +33,7 @@ describe(ConversionError, () => {
 
             // Assert
             expect(summary).toEqual(
-                `Error: multiple output eslint-rule ESLint rule options were generated, but tslint-to-eslint-config doesn't have "merger" logic to deal with this.${EOL}Please file an issue at https://github.com/typescript-eslint/tslint-to-eslint-config/issues/new?template=missing_merger.md 🙏`,
+                `Error: multiple output eslint-rule ESLint rule options were generated, but tslint-to-eslint-config doesn't have "merger" logic to deal with this.${EOL}Please file an issue at https://github.com/typescript-eslint/tslint-to-eslint-config/issues/new?template=missing_merger.md. Thanks!`,
             );
         });
     });
diff --git a/src/reporting/reportConversionResults.test.ts b/src/reporting/reportConversionResults.test.ts
index bc98079..466d8dc 100644
--- a/src/reporting/reportConversionResults.test.ts
+++ b/src/reporting/reportConversionResults.test.ts
@@ -19,7 +19,7 @@ describe("reportConversionResults", () => {
         const conversionResults = createEmptyConversionResults({
             converted: new Map<string, ESLintRuleOptions>([
                 [
-                    "tslint-rule-one",
+                    `tslint-rule-one`,
                     {
                         ruleArguments: ["a", "b"],
                         ruleName: "tslint-rule-one",
@@ -32,7 +32,11 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
@@ -49,7 +53,7 @@ describe("reportConversionResults", () => {
         const conversionResults = createEmptyConversionResults({
             converted: new Map<string, ESLintRuleOptions>([
                 [
-                    "tslint-rule-one",
+                    `tslint-rule-one`,
                     {
                         notices: ["1", "2"],
                         ruleArguments: ["a", "b"],
@@ -63,20 +67,29 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
             logger.stdout.write,
             `✨ 1 rule replaced with its ESLint equivalent. ✨${EOL}`,
             `❗ 1 ESLint rule behaves differently from its TSLint counterpart ❗`,
-            `  * tslint-rule-one:`,
-            `    - 1`,
-            `    - 2`,
+            `  Check ${logger.debugFileName} for details.`,
             ``,
             `⚡ 3 packages are required for running with ESLint. ⚡`,
             `  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
         );
+        expectEqualWrites(
+            logger.info.write,
+            `1 ESLint rule behaves differently from its TSLint counterpart:`,
+            `  * tslint-rule-one:`,
+            `    - 1`,
+            `    - 2`,
+        );
     });
 
     it("logs successful conversions when there are multiple converted rules", async () => {
@@ -84,7 +97,7 @@ describe("reportConversionResults", () => {
         const conversionResults = createEmptyConversionResults({
             converted: new Map<string, ESLintRuleOptions>([
                 [
-                    "tslint-rule-one",
+                    `tslint-rule-one`,
                     {
                         notices: ["1", "2"],
                         ruleArguments: ["a", "b"],
@@ -93,7 +106,7 @@ describe("reportConversionResults", () => {
                     },
                 ],
                 [
-                    "tslint-rule-two",
+                    `tslint-rule-two`,
                     {
                         notices: ["3", "4"],
                         ruleArguments: ["c", "d"],
@@ -107,7 +120,11 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
@@ -115,15 +132,20 @@ describe("reportConversionResults", () => {
             `✨ 2 rules replaced with their ESLint equivalents. ✨`,
             ``,
             `❗ 2 ESLint rules behave differently from their TSLint counterparts ❗`,
+            `  Check ${logger.debugFileName} for details.`,
+            ``,
+            `⚡ 3 packages are required for running with ESLint. ⚡`,
+            `  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
+        );
+        expectEqualWrites(
+            logger.info.write,
+            `2 ESLint rules behave differently from their TSLint counterparts:`,
             `  * tslint-rule-one:`,
             `    - 1`,
             `    - 2`,
             `  * tslint-rule-two:`,
             `    - 3`,
             `    - 4`,
-            ``,
-            `⚡ 3 packages are required for running with ESLint. ⚡`,
-            `  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
         );
     });
 
@@ -136,12 +158,16 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
             logger.stderr.write,
-            "❌ 1 error thrown. ❌",
+            `❌ 1 error thrown. ❌`,
             `  Check ${logger.debugFileName} for details.`,
         );
     });
@@ -155,12 +181,16 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
             logger.stderr.write,
-            "❌ 2 errors thrown. ❌",
+            `❌ 2 errors thrown. ❌`,
             `  Check ${logger.debugFileName} for details.`,
         );
     });
@@ -180,20 +210,26 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
             logger.stdout.write,
-            "❓ 1 rule does not yet have an ESLint equivalent ❓",
-            `  See generated log file; defaulting to eslint-plugin-tslint for it.`,
-            "",
-            "⚡ 3 packages are required for running with ESLint. ⚡",
-            "  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev",
+            `❓ 1 rule is not known by tslint-to-eslint-config to have an ESLint equivalent. ❓`,
+            `  The "@typescript-eslint/tslint/config" section of .eslintrc.js configures eslint-plugin-tslint to run it in TSLint within ESLint.`,
+            `  Check ${logger.debugFileName} for details.`,
+            ``,
+            `⚡ 3 packages are required for running with ESLint. ⚡`,
+            `  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
         );
         expectEqualWrites(
             logger.info.write,
-            'tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-rule-one"',
+            `1 rule is not known by tslint-to-eslint-config to have an ESLint equivalent:`,
+            '  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-rule-one".',
         );
     });
 
@@ -217,21 +253,27 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
             logger.stdout.write,
-            "❓ 2 rules do not yet have ESLint equivalents ❓",
-            `  See generated log file; defaulting to eslint-plugin-tslint for these rules.`,
-            "",
-            "⚡ 3 packages are required for running with ESLint. ⚡",
-            "  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev",
+            `❓ 2 rules are not known by tslint-to-eslint-config to have ESLint equivalents. ❓`,
+            `  The "@typescript-eslint/tslint/config" section of .eslintrc.js configures eslint-plugin-tslint to run them in TSLint within ESLint.`,
+            `  Check ${logger.debugFileName} for details.`,
+            ``,
+            `⚡ 3 packages are required for running with ESLint. ⚡`,
+            `  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint --dev`,
         );
         expectEqualWrites(
             logger.info.write,
-            'tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-rule-one"',
-            'tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-rule-two"',
+            `2 rules are not known by tslint-to-eslint-config to have ESLint equivalents:`,
+            '  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-rule-one".',
+            '  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-rule-two".',
         );
     });
 
@@ -244,13 +286,17 @@ describe("reportConversionResults", () => {
         const { choosePackageManager, logger } = createStubDependencies();
 
         // Act
-        await reportConversionResults({ choosePackageManager, logger }, conversionResults);
+        await reportConversionResults(
+            { choosePackageManager, logger },
+            ".eslintrc.js",
+            conversionResults,
+        );
 
         // Assert
         expectEqualWrites(
             logger.stdout.write,
-            "⚡ 5 packages are required for running with ESLint. ⚡",
-            "  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint plugin-one plugin-two --dev",
+            `⚡ 5 packages are required for running with ESLint. ⚡`,
+            `  yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint plugin-one plugin-two --dev`,
         );
     });
 });
diff --git a/src/reporting/reportEditorSettingConversionResults.test.ts b/src/reporting/reportEditorSettingConversionResults.test.ts
index 9bbff13..a4ced16 100644
--- a/src/reporting/reportEditorSettingConversionResults.test.ts
+++ b/src/reporting/reportEditorSettingConversionResults.test.ts
@@ -121,12 +121,13 @@ describe("reportEditorSettingConversionResults", () => {
         // Assert
         expectEqualWrites(
             logger.stdout.write,
-            `❓ 1 editor setting does not yet have an ESLint equivalent ❓`,
-            `  See generated log file.`,
+            `❓ 1 editor setting is not known by tslint-to-eslint-config to have an ESLint equivalent. ❓`,
+            `  Check ${logger.debugFileName} for details.`,
         );
         expectEqualWrites(
             logger.info.write,
-            'tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-editor-setting-one"',
+            `1 editor setting is not known by tslint-to-eslint-config to have an ESLint equivalent:`,
+            '  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-editor-setting-one".',
         );
     });
 
@@ -151,13 +152,14 @@ describe("reportEditorSettingConversionResults", () => {
         // Assert
         expectEqualWrites(
             logger.stdout.write,
-            `❓ 2 editor settings do not yet have ESLint equivalents ❓`,
-            `  See generated log file.`,
+            `❓ 2 editor settings are not known by tslint-to-eslint-config to have ESLint equivalents. ❓`,
+            `  Check ${logger.debugFileName} for details.`,
         );
         expectEqualWrites(
             logger.info.write,
-            'tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-editor-setting-one"',
-            'tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-editor-setting-two"',
+            `2 editor settings are not known by tslint-to-eslint-config to have ESLint equivalents:`,
+            '  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-editor-setting-one".',
+            '  * tslint-to-eslint-config does not know the ESLint equivalent for TSLint\'s "tslint-editor-setting-two".',
         );
     });
 });