Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save maddada/8e064cf31e5dce26cb5166f0af24ca3c to your computer and use it in GitHub Desktop.

Select an option

Save maddada/8e064cf31e5dce26cb5166f0af24ca3c to your computer and use it in GitHub Desktop.
#!/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