@samitouri / QOS-React / commits / c464445b91

[healthcheck] Check for incompatible libraries

Add a configurable list of known incompatible libraries. Check all package.jsons for any uses of known incompatible libraries and warn if found. ghstack-source-id: 7329e3792b57458e681780cba3140a14a9b1a60d Pull Request resolved: https://github.com/facebook/react-forget/pull/2923

Sathya Gunsasekaran committed May 1, 2024 at 15:34 UTC c464445b91d0d19ed00ecb81d993666495a5191f
3 files changed +50 -10
compiler/packages/healthcheck/package.json
+1
@@ -7,6 +7,7 @@
7 "test": "echo 'no tests'"
8 },
9 "dependencies": {
10 + "chalk": "4",
11 "fast-glob": "^3.3.2",
12 "ora": "5.4.1",
13 "yargs": "^17.7.2"
compiler/packages/healthcheck/src/config.ts new
+3
@@ -0,0 +1,3 @@
1 +export const config = {
2 + knownIncompatibleLibraries: ["mobx"],
3 +};
compiler/packages/healthcheck/src/index.ts
+46 -10
@@ -12,10 +12,12 @@ import {
12 type PluginOptions,
13 } from "babel-plugin-react-forget/src";
14 import { LoggerEvent } from "babel-plugin-react-forget/src/Entrypoint";
15 +import chalk from "chalk";
16 import { glob } from "fast-glob";
17 import * as fs from "fs/promises";
18 import ora from "ora";
19 import yargs from "yargs/yargs";
20 +import { config } from "./config";
21
22 const SUCCESS: Array<LoggerEvent> = [];
23 const ACTIONABLE_FAILURES: Array<LoggerEvent> = [];
@@ -41,7 +43,8 @@ const logger = {
43 }
44 case "CompileDiagnostic":
45 case "PipelineError":
44 - // TODO(gsn): Silenty fail?
46 + OTHER_FAILURES.push(event);
47 + return;
48 }
49 },
50 };
@@ -86,7 +89,7 @@ async function main() {
89 .option("src", {
90 description: "glob expression matching src files to compile",
91 type: "string",
89 - default: "**/*.{js,ts,jsx,tsx,mjs}",
92 + default: "**/*.*",
93 })
94 .parseSync();
95
@@ -95,7 +98,7 @@ async function main() {
98
99 // no file extension specified
100 if (!src.includes(".")) {
98 - src = src + ".{js,ts,jsx,tsx,mjs}";
101 + src = src;
102 }
103
104 const globOptions = {
@@ -112,20 +115,53 @@ async function main() {
115 ],
116 };
117
118 + const jsFileExtensionRE = /(js|ts|jsx|tsx|mjs)$/;
119 + const packageJsonRE = /package\.json$/;
120 + const knownIncompatibleLibrariesUsage = new Set();
121 +
122 for (const path of await glob(src, globOptions)) {
123 const source = await fs.readFile(path, "utf-8");
117 - spinner.text = `Compiling ${path}`;
118 - compile(source, path);
124 + if (jsFileExtensionRE.exec(path) !== null) {
125 + spinner.text = `Compiling ${path}`;
126 + compile(source, path);
127
120 - if (!STRICT_MODE_USAGE) {
121 - STRICT_MODE_USAGE = StrictModeRE.exec(source) !== null;
128 + if (!STRICT_MODE_USAGE) {
129 + STRICT_MODE_USAGE = StrictModeRE.exec(source) !== null;
130 + }
131 + } else if (packageJsonRE.exec(path) !== null) {
132 + const contents = JSON.parse(source);
133 + const deps = contents.dependencies;
134 + for (const library of config.knownIncompatibleLibraries) {
135 + if (Object.hasOwn(deps, library)) {
136 + knownIncompatibleLibrariesUsage.add(library);
137 + }
138 + }
139 }
140 }
141 spinner.stop();
142
126 - console.log(`Successful compilation: ${SUCCESS.length}`);
127 - console.log(`Failed compilation: ${ACTIONABLE_FAILURES.length}`);
128 - console.log(`StrictMode usage: ${STRICT_MODE_USAGE}`);
143 + const totalComponents =
144 + SUCCESS.length + OTHER_FAILURES.length + ACTIONABLE_FAILURES.length;
145 + console.log(
146 + chalk.green(
147 + `Successfully compiled ${SUCCESS.length} out of ${totalComponents} components.`
148 + )
149 + );
150 +
151 + if (STRICT_MODE_USAGE) {
152 + console.log(chalk.green("StrictMode usage found."));
153 + } else {
154 + console.log(chalk.red("StrictMode usage not found."));
155 + }
156 +
157 + if (knownIncompatibleLibrariesUsage.size > 0) {
158 + console.log(chalk.red(`Found the following incompatible libraries:`));
159 + for (const library of knownIncompatibleLibrariesUsage) {
160 + console.log(library);
161 + }
162 + } else {
163 + console.log(chalk.green(`Found no usage of incompatible libraries.`));
164 + }
165 }
166
167 main();