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

Issue:
Cannot read package files on Windows
### 🐛 Bug Report

-   `tslint-to-eslint-config` version: 2.6.0
-   ESLint version: N/A
-   Node version: 12.X, 14.X

#### Actual Behavior

When trying to find `package.json` dependencies, `cat path/to/package.json` is a CLI command that gets run.

#### Expected Behavior

`cat` doesn't exist on Windows.

#### Reproduction

On Windows, `npx tslint-to-eslint-config` and see the error in `findOriginalConfigurations` for `package`.

Spotted in #1149.

Pull request description:
Fixed package file parsing for Windows
## PR Checklist

-   [x] Addresses an existing issue: fixes #1150
-   [x] That issue was marked as [`status: accepting prs`](https://github.com/typescript-eslint/tslint-to-eslint-config/labels/status%3A%20accepting%20prs)

## Overview

Uses the `fsFileSystem` instead of CLI output parsing.


Patch:
diff --git a/src/api/dependencies.ts b/src/api/dependencies.ts
index 854c8c2..4c74cb3 100644
--- a/src/api/dependencies.ts
+++ b/src/api/dependencies.ts
@@ -110,9 +110,13 @@ export const findConfigurationDependencies = {
     importer: boundImporter,
 };
 
+export const findPackagesConfigurationDependencies = {
+    fileSystem: fsFileSystem,
+};
+
 export const findOriginalConfigurationsDependencies: FindOriginalConfigurationsDependencies = {
     findESLintConfiguration: bind(findESLintConfiguration, findConfigurationDependencies),
-    findPackagesConfiguration: bind(findPackagesConfiguration, findConfigurationDependencies),
+    findPackagesConfiguration: bind(findPackagesConfiguration, findPackagesConfigurationDependencies),
     findTypeScriptConfiguration: bind(findTypeScriptConfiguration, findConfigurationDependencies),
     findTSLintConfiguration: bind(findTSLintConfiguration, findConfigurationDependencies),
     mergeLintConfigurations,
diff --git a/src/input/findPackagesConfiguration.ts b/src/input/findPackagesConfiguration.ts
index 5e614e0..89ad2f3 100644
--- a/src/input/findPackagesConfiguration.ts
+++ b/src/input/findPackagesConfiguration.ts
@@ -1,31 +1,31 @@
-import {
-    findReportedConfiguration,
-    FindReportedConfigurationDependencies,
-} from "./findReportedConfiguration";
+import { FileSystem } from "../adapters/fileSystem";
 
 export type PackagesConfiguration = {
     dependencies: Record<string, string | undefined>;
     devDependencies: Record<string, string | undefined>;
 };
 
+export type FindPackagesConfigurationDependencies = {
+    fileSystem: Pick<FileSystem, "readFile">;
+}
+
 export const findPackagesConfiguration = async (
-    dependencies: FindReportedConfigurationDependencies,
-    config: string | undefined,
+    dependencies: FindPackagesConfigurationDependencies,
+    config = "./package.json",
 ): Promise<PackagesConfiguration | Error> => {
-    const rawConfiguration = await findReportedConfiguration<PackagesConfiguration>(
-        dependencies.exec,
-        "cat",
-        config ?? "./package.json",
-    );
+    const rawConfiguration = await dependencies.fileSystem.readFile(config);
+    if (rawConfiguration instanceof Error) {
+        return rawConfiguration;
+    }
+
+    const configuration = (JSON.parse(rawConfiguration)) as PackagesConfiguration;
 
-    return rawConfiguration instanceof Error
-        ? rawConfiguration
-        : {
-              dependencies: {
-                  ...rawConfiguration.dependencies,
-              },
-              devDependencies: {
-                  ...rawConfiguration.devDependencies,
-              },
-          };
+    return {
+        dependencies: {
+            ...configuration.dependencies,
+        },
+        devDependencies: {
+            ...configuration.devDependencies,
+        },
+    };
 };


Test patch:
diff --git a/src/input/findPackagesConfiguration.test.ts b/src/input/findPackagesConfiguration.test.ts
index 767227a..6321093 100644
--- a/src/input/findPackagesConfiguration.test.ts
+++ b/src/input/findPackagesConfiguration.test.ts
@@ -1,33 +1,62 @@
-import { createStubExec } from "../adapters/exec.stubs";
+import { createStubFileSystem } from "../adapters/fileSystem.stub";
 import { findPackagesConfiguration } from "./findPackagesConfiguration";
 
 describe("findPackagesConfiguration", () => {
     it("defaults the configuration file when one isn't provided", async () => {
         // Arrange
-        const dependencies = { exec: createStubExec() };
+        const dependencies = {
+            fileSystem: createStubFileSystem({
+                data: "{}"
+            })
+        }
 
         // Act
         await findPackagesConfiguration(dependencies, undefined);
 
         // Assert
-        expect(dependencies.exec).toHaveBeenLastCalledWith(`cat "./package.json"`);
+        expect(dependencies.fileSystem.readFile).toHaveBeenLastCalledWith(`./package.json`);
     });
 
-    it("includes a configuration file in the packages command when one is provided", async () => {
+    it("uses the configuration file from the packages command when one is provided", async () => {
         // Arrange
-        const dependencies = { exec: createStubExec() };
+        const dependencies = {
+            fileSystem: createStubFileSystem({
+                data: "{}"
+            })
+        }
         const config = "./custom/package.json";
 
         // Act
         await findPackagesConfiguration(dependencies, config);
 
         // Assert
-        expect(dependencies.exec).toHaveBeenLastCalledWith(`cat "./custom/package.json"`);
+        expect(dependencies.fileSystem.readFile).toHaveBeenLastCalledWith(`./custom/package.json`);
+    });
+
+    it("returns an error when readFile returns an error", async () => {
+        // Arrange
+        const error = new Error("Oh no!");
+        const dependencies = {
+            fileSystem: createStubFileSystem({
+                data: error
+            })
+        }
+        const config = "./custom/package.json";
+
+        // Act
+        const result = await findPackagesConfiguration(dependencies, config);
+
+        // Assert
+        expect(result).toBe(error);
     });
 
     it("applies packages defaults when none are provided", async () => {
         // Arrange
-        const dependencies = { exec: createStubExec({ stdout: "{}" }) };
+        const dependencies = {
+            fileSystem: createStubFileSystem({
+                data: "{}"
+            })
+        }
         const config = "./package.json";
 
         // Act
@@ -39,4 +68,28 @@ describe("findPackagesConfiguration", () => {
             devDependencies: {},
         });
     });
+
+    it("uses existing package data when it exists", async () => {
+        // Arrange
+        const data = {
+            dependencies: {
+                eslint: "^11.22.33",
+            },
+            devDependencies: {
+                tslint: "^12.34.56"
+            }
+        }
+        const dependencies = {
+            fileSystem: createStubFileSystem({
+                data: JSON.stringify(data)
+            })
+        }
+        const config = "./package.json";
+
+        // Act
+        const result = await findPackagesConfiguration(dependencies, config);
+
+        // Assert
+        expect(result).toEqual(data);
+    });
 });