Skip to content

Instantly share code, notes, and snippets.

@mekwall
Last active November 23, 2022 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mekwall/6c40252a16facc4f896feb564083f75d to your computer and use it in GitHub Desktop.
Save mekwall/6c40252a16facc4f896feb564083f75d to your computer and use it in GitHub Desktop.
Rename js files with @flow header to ts/tsx
import { Stats } from "fs";
import { readdir, lstat, readFile, rename } from "fs/promises";
import path from "path";
import { transformAsync } from "@babel/core";
const isDry = !!process.argv.find((a) => a.includes("--dry"));
const jsExtRegex = /\.(js)$/;
async function* walkPath(
basePath: string
): AsyncIterableIterator<{ path: string; stat: Promise<Stats> }> {
try {
for (const currentPath of await readdir(path.normalize(basePath))) {
const fullPath = path.resolve(basePath, currentPath);
const stat = lstat(fullPath);
yield { path: fullPath, stat };
}
} catch {
// Ignore
}
}
interface PathWalkerOptions {
yieldDir?: boolean;
yieldFile?: boolean;
depth?: number;
}
export async function* pathWalker(
basePath: string,
options: PathWalkerOptions = {}
): AsyncGenerator<string> {
const { yieldDir = false, yieldFile = true, depth = Infinity } = options;
try {
for await (const { path, stat } of walkPath(basePath)) {
const s = await stat;
if (s.isDirectory()) {
if (depth > 1) {
yield* pathWalker(path, { ...options, depth: depth - 1 });
}
if (yieldDir) {
yield path;
}
} else if (s.isFile() && yieldFile) {
yield path;
}
}
} catch {
// Ignore
}
}
async function main() {
for (const sourceDir of ["./src", "./scripts"]) {
for await (const filePath of pathWalker(
path.resolve(process.cwd(), sourceDir)
)) {
const isJsFile = jsExtRegex.test(filePath);
if (isJsFile) {
const content = await readFile(filePath, "utf8");
const isFlow = content.includes("// @flow");
if (isFlow) {
// strip flow types from content string using babel
const result = await transformAsync(content, {
filename: filePath,
plugins: [
"@babel/plugin-transform-flow-strip-types",
[
"@babel/plugin-transform-react-jsx",
{
runtime: "automatic",
},
],
],
});
if (filePath.includes("Camera.js")) {
console.log("isFlow", isFlow);
}
const code = result?.code || "";
const isJSX =
code.includes("react/jsx-runtime") ||
code.includes("React.Fragment") ||
code.includes("React.createElement");
const ext = isJSX ? "tsx" : "ts";
const newFilePath = filePath.replace(/\.js$/, `.${ext}`);
console.log(`${filePath} -> ${newFilePath}`);
if (!isDry) {
await rename(filePath, newFilePath);
}
}
}
}
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment