mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[healthcheck] Refactor checks into separate files
Makes it easier to extend later, if we want to add more checks. ghstack-source-id: 6fb3435555f1b988e1a185bfda8be9418eb622c5 Pull Request resolved: https://github.com/facebook/react-forget/pull/2924
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import chalk from "chalk";
|
||||
import { config } from "../config";
|
||||
|
||||
const packageJsonRE = /package\.json$/;
|
||||
const knownIncompatibleLibrariesUsage = new Set();
|
||||
|
||||
export default {
|
||||
run(source: string, path: string): void {
|
||||
if (packageJsonRE.exec(path) !== null) {
|
||||
const contents = JSON.parse(source);
|
||||
const deps = contents.dependencies;
|
||||
for (const library of config.knownIncompatibleLibraries) {
|
||||
if (Object.hasOwn(deps, library)) {
|
||||
knownIncompatibleLibrariesUsage.add(library);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
report(): void {
|
||||
if (knownIncompatibleLibrariesUsage.size > 0) {
|
||||
console.log(chalk.red(`Found the following incompatible libraries:`));
|
||||
for (const library of knownIncompatibleLibrariesUsage) {
|
||||
console.log(library);
|
||||
}
|
||||
} else {
|
||||
console.log(chalk.green(`Found no usage of incompatible libraries.`));
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {
|
||||
ErrorSeverity,
|
||||
runReactForgetBabelPlugin,
|
||||
type CompilerErrorDetailOptions,
|
||||
type PluginOptions,
|
||||
} from "babel-plugin-react-forget/src";
|
||||
import { LoggerEvent } from "babel-plugin-react-forget/src/Entrypoint";
|
||||
import chalk from "chalk";
|
||||
|
||||
const SucessfulCompilation: Array<LoggerEvent> = [];
|
||||
const ActionableFailures: Array<LoggerEvent> = [];
|
||||
const OtherFailures: Array<LoggerEvent> = [];
|
||||
|
||||
const logger = {
|
||||
logEvent(_: string | null, event: LoggerEvent) {
|
||||
switch (event.kind) {
|
||||
case "CompileSuccess": {
|
||||
SucessfulCompilation.push(event);
|
||||
return;
|
||||
}
|
||||
case "CompileError": {
|
||||
if (isActionableDiagnostic(event.detail)) {
|
||||
ActionableFailures.push(event);
|
||||
return;
|
||||
}
|
||||
OtherFailures.push(event);
|
||||
return;
|
||||
}
|
||||
case "CompileDiagnostic":
|
||||
case "PipelineError":
|
||||
OtherFailures.push(event);
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const COMPILER_OPTIONS: Partial<PluginOptions> = {
|
||||
noEmit: true,
|
||||
compilationMode: "infer",
|
||||
panicThreshold: "critical_errors",
|
||||
logger,
|
||||
};
|
||||
|
||||
function isActionableDiagnostic(detail: CompilerErrorDetailOptions) {
|
||||
switch (detail.severity) {
|
||||
case ErrorSeverity.InvalidReact:
|
||||
case ErrorSeverity.InvalidJS:
|
||||
return true;
|
||||
case ErrorSeverity.InvalidConfig:
|
||||
case ErrorSeverity.Invariant:
|
||||
case ErrorSeverity.CannotPreserveMemoization:
|
||||
case ErrorSeverity.Todo:
|
||||
return false;
|
||||
default:
|
||||
throw new Error("Unhandled error severity");
|
||||
}
|
||||
}
|
||||
|
||||
function compile(sourceCode: string, filename: string) {
|
||||
try {
|
||||
runReactForgetBabelPlugin(
|
||||
sourceCode,
|
||||
filename,
|
||||
"typescript",
|
||||
COMPILER_OPTIONS
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const JsFileExtensionRE = /(js|ts|jsx|tsx|mjs)$/;
|
||||
|
||||
export default {
|
||||
run(source: string, path: string): void {
|
||||
if (JsFileExtensionRE.exec(path) !== null) {
|
||||
compile(source, path);
|
||||
}
|
||||
},
|
||||
|
||||
report(): void {
|
||||
const totalComponents =
|
||||
SucessfulCompilation.length +
|
||||
OtherFailures.length +
|
||||
ActionableFailures.length;
|
||||
console.log(
|
||||
chalk.green(
|
||||
`Successfully compiled ${SucessfulCompilation.length} out of ${totalComponents} components.`
|
||||
)
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import chalk from "chalk";
|
||||
|
||||
const JsFileExtensionRE = /(js|ts|jsx|tsx|mjs)$/;
|
||||
const StrictModeRE = /\<StrictMode\>/;
|
||||
let StrictModeUsage = false;
|
||||
|
||||
export default {
|
||||
run(source: string, path: string): void {
|
||||
if (JsFileExtensionRE.exec(path) === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StrictModeUsage) {
|
||||
StrictModeUsage = StrictModeRE.exec(source) !== null;
|
||||
}
|
||||
},
|
||||
|
||||
report(): void {
|
||||
if (StrictModeUsage) {
|
||||
console.log(chalk.green("StrictMode usage found."));
|
||||
} else {
|
||||
console.log(chalk.red("StrictMode usage not found."));
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -5,82 +5,13 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {
|
||||
ErrorSeverity,
|
||||
runReactForgetBabelPlugin,
|
||||
type CompilerErrorDetailOptions,
|
||||
type PluginOptions,
|
||||
} from "babel-plugin-react-forget/src";
|
||||
import { LoggerEvent } from "babel-plugin-react-forget/src/Entrypoint";
|
||||
import chalk from "chalk";
|
||||
import { glob } from "fast-glob";
|
||||
import * as fs from "fs/promises";
|
||||
import ora from "ora";
|
||||
import yargs from "yargs/yargs";
|
||||
import { config } from "./config";
|
||||
|
||||
const SUCCESS: Array<LoggerEvent> = [];
|
||||
const ACTIONABLE_FAILURES: Array<LoggerEvent> = [];
|
||||
const OTHER_FAILURES: Array<LoggerEvent> = [];
|
||||
let STRICT_MODE_USAGE = false;
|
||||
|
||||
const StrictModeRE = /\<StrictMode\>/;
|
||||
|
||||
const logger = {
|
||||
logEvent(_: string | null, event: LoggerEvent) {
|
||||
switch (event.kind) {
|
||||
case "CompileSuccess": {
|
||||
SUCCESS.push(event);
|
||||
return;
|
||||
}
|
||||
case "CompileError": {
|
||||
if (isActionableDiagnostic(event.detail)) {
|
||||
ACTIONABLE_FAILURES.push(event);
|
||||
return;
|
||||
}
|
||||
OTHER_FAILURES.push(event);
|
||||
return;
|
||||
}
|
||||
case "CompileDiagnostic":
|
||||
case "PipelineError":
|
||||
OTHER_FAILURES.push(event);
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const COMPILER_OPTIONS: Partial<PluginOptions> = {
|
||||
noEmit: true,
|
||||
compilationMode: "infer",
|
||||
panicThreshold: "critical_errors",
|
||||
logger,
|
||||
};
|
||||
|
||||
function isActionableDiagnostic(detail: CompilerErrorDetailOptions) {
|
||||
switch (detail.severity) {
|
||||
case ErrorSeverity.InvalidReact:
|
||||
case ErrorSeverity.InvalidJS:
|
||||
return true;
|
||||
case ErrorSeverity.InvalidConfig:
|
||||
case ErrorSeverity.Invariant:
|
||||
case ErrorSeverity.CannotPreserveMemoization:
|
||||
case ErrorSeverity.Todo:
|
||||
return false;
|
||||
default:
|
||||
throw new Error("Unhandled error severity");
|
||||
}
|
||||
}
|
||||
|
||||
function compile(sourceCode: string, filename: string) {
|
||||
try {
|
||||
runReactForgetBabelPlugin(
|
||||
sourceCode,
|
||||
filename,
|
||||
"typescript",
|
||||
COMPILER_OPTIONS
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
import libraryCompatCheck from "./checks/libraryCompat";
|
||||
import reactCompilerCheck from "./checks/reactCompiler";
|
||||
import strictModeCheck from "./checks/strictMode";
|
||||
|
||||
async function main() {
|
||||
const argv = yargs(process.argv.slice(2))
|
||||
@@ -93,14 +24,9 @@ async function main() {
|
||||
})
|
||||
.parseSync();
|
||||
|
||||
const spinner = ora("Compiling").start();
|
||||
const spinner = ora("Checking").start();
|
||||
let src = argv.src;
|
||||
|
||||
// no file extension specified
|
||||
if (!src.includes(".")) {
|
||||
src = src;
|
||||
}
|
||||
|
||||
const globOptions = {
|
||||
onlyFiles: true,
|
||||
ignore: [
|
||||
@@ -115,53 +41,18 @@ async function main() {
|
||||
],
|
||||
};
|
||||
|
||||
const jsFileExtensionRE = /(js|ts|jsx|tsx|mjs)$/;
|
||||
const packageJsonRE = /package\.json$/;
|
||||
const knownIncompatibleLibrariesUsage = new Set();
|
||||
|
||||
for (const path of await glob(src, globOptions)) {
|
||||
const source = await fs.readFile(path, "utf-8");
|
||||
if (jsFileExtensionRE.exec(path) !== null) {
|
||||
spinner.text = `Compiling ${path}`;
|
||||
compile(source, path);
|
||||
|
||||
if (!STRICT_MODE_USAGE) {
|
||||
STRICT_MODE_USAGE = StrictModeRE.exec(source) !== null;
|
||||
}
|
||||
} else if (packageJsonRE.exec(path) !== null) {
|
||||
const contents = JSON.parse(source);
|
||||
const deps = contents.dependencies;
|
||||
for (const library of config.knownIncompatibleLibraries) {
|
||||
if (Object.hasOwn(deps, library)) {
|
||||
knownIncompatibleLibrariesUsage.add(library);
|
||||
}
|
||||
}
|
||||
}
|
||||
spinner.text = `Checking ${path}`;
|
||||
reactCompilerCheck.run(source, path);
|
||||
strictModeCheck.run(source, path);
|
||||
libraryCompatCheck.run(source, path);
|
||||
}
|
||||
spinner.stop();
|
||||
|
||||
const totalComponents =
|
||||
SUCCESS.length + OTHER_FAILURES.length + ACTIONABLE_FAILURES.length;
|
||||
console.log(
|
||||
chalk.green(
|
||||
`Successfully compiled ${SUCCESS.length} out of ${totalComponents} components.`
|
||||
)
|
||||
);
|
||||
|
||||
if (STRICT_MODE_USAGE) {
|
||||
console.log(chalk.green("StrictMode usage found."));
|
||||
} else {
|
||||
console.log(chalk.red("StrictMode usage not found."));
|
||||
}
|
||||
|
||||
if (knownIncompatibleLibrariesUsage.size > 0) {
|
||||
console.log(chalk.red(`Found the following incompatible libraries:`));
|
||||
for (const library of knownIncompatibleLibrariesUsage) {
|
||||
console.log(library);
|
||||
}
|
||||
} else {
|
||||
console.log(chalk.green(`Found no usage of incompatible libraries.`));
|
||||
}
|
||||
reactCompilerCheck.report();
|
||||
strictModeCheck.report();
|
||||
libraryCompatCheck.report();
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
Reference in New Issue
Block a user