Last active
April 24, 2025 17:47
-
-
Save maddada/8e064cf31e5dce26cb5166f0af24ca3c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| /** | |
| * 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. | |
| * | |
| * @lightSyntaxTransform | |
| * @noflow | |
| * @nolint | |
| * @preventMunge | |
| * @preserve-invariant-messages | |
| */ | |
| "use no memo"; | |
| "use strict"; | |
| var __create = Object.create; | |
| var __defProp = Object.defineProperty; | |
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | |
| var __getOwnPropNames = Object.getOwnPropertyNames; | |
| var __getProtoOf = Object.getPrototypeOf; | |
| var __hasOwnProp = Object.prototype.hasOwnProperty; | |
| var __copyProps = (to, from, except, desc) => { | |
| if (from && typeof from === "object" || typeof from === "function") { | |
| for (let key of __getOwnPropNames(from)) | |
| if (!__hasOwnProp.call(to, key) && key !== except) | |
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | |
| } | |
| return to; | |
| }; | |
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | |
| // If the importer is in node compatibility mode or this is not an ESM | |
| // file that has been converted to a CommonJS file using a Babel- | |
| // compatible transform (i.e. "__esModule" has not been set), then set | |
| // "default" to the CommonJS "module.exports" for node compatibility. | |
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | |
| mod | |
| )); | |
| var __async = (__this, __arguments, generator) => { | |
| return new Promise((resolve, reject) => { | |
| var fulfilled = (value) => { | |
| try { | |
| step(generator.next(value)); | |
| } catch (e) { | |
| reject(e); | |
| } | |
| }; | |
| var rejected = (value) => { | |
| try { | |
| step(generator.throw(value)); | |
| } catch (e) { | |
| reject(e); | |
| } | |
| }; | |
| var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); | |
| step((generator = generator.apply(__this, __arguments)).next()); | |
| }); | |
| }; | |
| // src/index.ts | |
| var import_fast_glob = require("fast-glob"); | |
| var fs = __toESM(require("fs/promises")); | |
| var import_ora = __toESM(require("ora")); | |
| var import_yargs = __toESM(require("yargs/yargs")); | |
| // src/checks/libraryCompat.ts | |
| var import_chalk = __toESM(require("chalk")); | |
| // src/config.ts | |
| var config = { | |
| knownIncompatibleLibraries: [ | |
| "mobx-react", | |
| "mobx-react-lite", | |
| "@risingstack/react-easy-state" | |
| ] | |
| }; | |
| // src/checks/libraryCompat.ts | |
| var packageJsonRE = /package\.json$/; | |
| var knownIncompatibleLibrariesUsage = /* @__PURE__ */ new Set(); | |
| var libraryCompat_default = { | |
| run(source, path) { | |
| if (packageJsonRE.exec(path) !== null) { | |
| const contents = JSON.parse(source); | |
| const deps = contents.dependencies; | |
| if (deps != null) { | |
| for (const library of config.knownIncompatibleLibraries) { | |
| if (Object.hasOwn(deps, library)) { | |
| knownIncompatibleLibrariesUsage.add(library); | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| report() { | |
| if (knownIncompatibleLibrariesUsage.size > 0) { | |
| console.log(import_chalk.default.red(`Found the following incompatible libraries:`)); | |
| for (const library of knownIncompatibleLibrariesUsage) { | |
| console.log(library); | |
| } | |
| } else { | |
| console.log(import_chalk.default.green(`Found no usage of incompatible libraries.`)); | |
| } | |
| } | |
| }; | |
| // src/checks/reactCompiler.ts | |
| var import_core = require("@babel/core"); | |
| var BabelParser = __toESM(require("@babel/parser")); | |
| var import_babel_plugin_react_compiler = __toESM(require("babel-plugin-react-compiler")); | |
| var import_chalk2 = __toESM(require("chalk")); | |
| var SucessfulCompilation = []; | |
| var ActionableFailures = []; | |
| var OtherFailures = []; | |
| var logger = { | |
| logEvent(_, event) { | |
| 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; | |
| } | |
| } | |
| }; | |
| var COMPILER_OPTIONS = { | |
| noEmit: true, | |
| compilationMode: "infer", | |
| panicThreshold: "critical_errors", | |
| logger | |
| }; | |
| function isActionableDiagnostic(detail) { | |
| switch (detail.severity) { | |
| case "InvalidReact" /* InvalidReact */: | |
| case "InvalidJS" /* InvalidJS */: | |
| return true; | |
| case "InvalidConfig" /* InvalidConfig */: | |
| case "Invariant" /* Invariant */: | |
| case "CannotPreserveMemoization" /* CannotPreserveMemoization */: | |
| case "Todo" /* Todo */: | |
| return false; | |
| default: | |
| throw new Error(`Unhandled error severity \`${detail.severity}\``); | |
| } | |
| } | |
| function runBabelPluginReactCompiler(text, file, language, options) { | |
| const ast = BabelParser.parse(text, { | |
| sourceFilename: file, | |
| plugins: [language, "jsx"], | |
| sourceType: "module" | |
| }); | |
| const result = (0, import_core.transformFromAstSync)(ast, text, { | |
| filename: file, | |
| highlightCode: false, | |
| retainLines: true, | |
| plugins: [[import_babel_plugin_react_compiler.default, options]], | |
| sourceType: "module" | |
| }); | |
| if ((result == null ? void 0 : result.code) == null) { | |
| throw new Error(`Expected BabelPluginReactForget to codegen successfully, got: ${result}`); | |
| } | |
| return result; | |
| } | |
| function compile(sourceCode, filename) { | |
| try { | |
| runBabelPluginReactCompiler(sourceCode, filename, "typescript", COMPILER_OPTIONS); | |
| } catch (e) { | |
| } | |
| } | |
| var JsFileExtensionRE = /(js|ts|jsx|tsx)$/; | |
| var reactCompiler_default = { | |
| run(source, path) { | |
| if (JsFileExtensionRE.exec(path) !== null) { | |
| compile(source, path); | |
| } | |
| }, | |
| report(verbose) { | |
| var _a, _b; | |
| const totalComponents = SucessfulCompilation.length + OtherFailures.length + ActionableFailures.length; | |
| console.log(import_chalk2.default.green(`Successfully compiled ${SucessfulCompilation.length} out of ${totalComponents} components.`)); | |
| if (verbose) { | |
| for (const compilation of [...SucessfulCompilation, ...ActionableFailures, ...OtherFailures]) { | |
| const filename = compilation.kind === "CompileSuccess" || compilation.kind === "CompileError" || compilation.kind === "CompileDiagnostic" || compilation.kind === "CompileSkip" || compilation.kind === "PipelineError" ? (_a = compilation.fnLoc) == null ? void 0 : _a.filename : void 0; | |
| if (compilation.kind === "CompileSuccess") { | |
| const name = compilation.fnName; | |
| const isHook = name == null ? void 0 : name.startsWith("use"); | |
| if (name) { | |
| console.log(import_chalk2.default.green(`Successfully compiled ${isHook ? "hook" : "component"} [${name}](${filename})`)); | |
| } else { | |
| console.log(import_chalk2.default.green(`Successfully compiled ${(_b = compilation.fnLoc) == null ? void 0 : _b.filename}`)); | |
| } | |
| } | |
| if (compilation.kind === "CompileError") { | |
| const reason = compilation.detail.description; | |
| console.log(import_chalk2.default.red(`Failed to compile ${filename}${reason ? ` | |
| Reason: ${reason}` : ""}`)); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| // src/checks/strictMode.ts | |
| var import_chalk3 = __toESM(require("chalk")); | |
| var JsFileExtensionRE2 = /(js|ts|jsx|tsx)$/; | |
| var NextConfigFileRE = /^next\.config\.(js|mjs)$/; | |
| var StrictModeRE = /<(React\.StrictMode|StrictMode)>/; | |
| var NextStrictModeRE = /reactStrictMode:\s*true/; | |
| var StrictModeUsage = false; | |
| var strictMode_default = { | |
| run(source, path) { | |
| if (StrictModeUsage) { | |
| return; | |
| } | |
| if (NextConfigFileRE.exec(path) !== null) { | |
| StrictModeUsage = NextStrictModeRE.exec(source) !== null; | |
| } else if (JsFileExtensionRE2.exec(path) !== null) { | |
| StrictModeUsage = StrictModeRE.exec(source) !== null; | |
| } | |
| }, | |
| report() { | |
| if (StrictModeUsage) { | |
| console.log(import_chalk3.default.green("StrictMode usage found.")); | |
| } else { | |
| console.log(import_chalk3.default.red("StrictMode usage not found.")); | |
| } | |
| } | |
| }; | |
| // src/index.ts | |
| function main() { | |
| return __async(this, null, function* () { | |
| const argv = (0, import_yargs.default)(process.argv.slice(2)).scriptName("healthcheck").usage("$ npx healthcheck <src>").option("src", { | |
| description: "glob expression matching src files to compile", | |
| type: "string", | |
| default: "**/+(*.{js,jsx,ts,tsx}|package.json)" | |
| }).option("verbose", { | |
| alias: "v", | |
| type: "boolean", | |
| default: false, | |
| description: "run with verbose logging" | |
| }).parseSync(); | |
| const spinner = (0, import_ora.default)("Checking").start(); | |
| let src = argv.src; | |
| const verbose = argv.verbose; | |
| const globOptions = { | |
| onlyFiles: true, | |
| ignore: [ | |
| "**/node_modules/**", | |
| "**/dist/**", | |
| "**/tests/**", | |
| "**/__tests__/**", | |
| "**/__mocks__/**", | |
| "**/__e2e__/**" | |
| ] | |
| }; | |
| for (const path of yield (0, import_fast_glob.glob)(src, globOptions)) { | |
| const source = yield fs.readFile(path, "utf-8"); | |
| spinner.text = `Checking ${path}`; | |
| reactCompiler_default.run(source, path); | |
| strictMode_default.run(source, path); | |
| libraryCompat_default.run(source, path); | |
| } | |
| spinner.stop(); | |
| reactCompiler_default.report(verbose); | |
| strictMode_default.report(); | |
| libraryCompat_default.report(); | |
| }); | |
| } | |
| main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment