UNPKG

radashi-helper

Version:
261 lines (252 loc) 7.14 kB
import { queryFuncs } from "./chunk-GDVGEOPF.js"; import { isBabelNode, loadRewired, require_lib, rewire } from "./chunk-OCHPTCP5.js"; import { pullRadashi } from "./chunk-FEUFDYD5.js"; import { botCommit, openInEditor } from "./chunk-CQEIEK2X.js"; import { stdio } from "./chunk-GGEXN2BI.js"; import { cwdRelative, projectFolders } from "./chunk-BKS73LZK.js"; import { debug, getEnv } from "./chunk-DSXY7YVB.js"; import { RadashiError, exec, log } from "./chunk-JLKIE3A2.js"; import { __toESM, defer, flat, memo, reduce, select, traverse, unique } from "./chunk-VOEQFXI5.js"; // src/fn-override.ts import { existsSync as existsSync2 } from "node:fs"; import { copyFile as copyFile2, mkdir as mkdir2 } from "node:fs/promises"; import { dirname as dirname2, join as join3 } from "node:path"; // src/rewired/rewireDependents.ts var import_parser = __toESM(require_lib(), 1); import { existsSync, readFileSync } from "node:fs"; import { copyFile, mkdir, writeFile } from "node:fs/promises"; import { dirname, join as join2 } from "node:path"; // src/util/getRadashiFuncPaths.ts import glob from "fast-glob"; import { join } from "node:path"; async function getRadashiFuncPaths(env) { const srcRoot = join(env.radashiDir ?? env.root, "src"); return select( (await glob("**/*.ts", { cwd: srcRoot })).sort(), (f) => f.replace(/\.ts$/, ""), (f) => f.includes("/") ); } // src/rewired/rewireDependents.ts async function rewireDependents(funcName, env, radashiFuncPaths) { if (!env.radashiDir) { throw new RadashiError("No upstream repository exists"); } radashiFuncPaths ??= await getRadashiFuncPaths(env); const parseImports = memo((filename) => { const fileContents = readFileSync(filename, "utf8"); const parseResult = (0, import_parser.parse)(fileContents, { plugins: [["typescript", { dts: false }]], sourceType: "module", sourceFilename: filename }); const importedNames = /* @__PURE__ */ new Set(); traverse(parseResult.program, (node, _key, _parent, context) => { if (isBabelNode(node)) { context.skip(); if (node.type === "ImportDeclaration" && node.source.value === "radashi") { for (const specifier of node.specifiers) { importedNames.add(specifier.imported?.name ?? specifier.local.name); } } } }); return importedNames; }); const findDependentFiles = memo( (funcName2, stack = []) => { const selected = select( radashiFuncPaths, (funcPath) => { const filename = join2(env.radashiDir, "src", funcPath + ".ts"); const importedNames = parseImports(filename); if (importedNames.has(funcName2)) { let dependents = []; if (!stack.includes(funcPath)) { stack.push(funcPath); const srcFuncName = funcPath.split("/").at(-1); dependents = findDependentFiles(srcFuncName, stack); stack.pop(); } dependents.unshift(funcPath); return dependents; } return null; } ); return unique(flat(selected)); }, { key: (bestMatchName) => bestMatchName } ); const prevRewired = await loadRewired(env); const dependentFiles = findDependentFiles(funcName).filter((file) => { return !prevRewired.includes(file) && !existsSync(join2(env.overrideDir, "src", file + ".ts")); }).sort(); if (!dependentFiles.length) { return []; } await writeFile( join2(env.overrideDir, "rewired.json"), JSON.stringify([...prevRewired, ...dependentFiles], null, 2) ); await tryCopyFile( join2(env.root, "src/tsconfig.json"), join2(env.root, "overrides/rewired/tsconfig.json") ); return reduce( dependentFiles, async (copiedFiles, file) => { if (await rewire(file, env)) { copiedFiles.push(file); } return copiedFiles; }, [] ); } async function tryCopyFile(src, dst) { debug(`Copying ${cwdRelative(src)} to ${cwdRelative(dst)}`); if (existsSync(src)) { try { await mkdir(dirname(dst), { recursive: true }); await copyFile(src, dst); return true; } catch { } } return false; } // src/util/isRepoClean.ts import { exec as exec2 } from "node:child_process"; async function isRepoClean(cwd) { return new Promise((resolve, reject) => { exec2("git status --porcelain", { cwd }, (error, stdout, stderr) => { if (error) { reject(new Error(`Error executing git status: ${stderr}`)); } else { resolve(stdout.trim() === ""); } }); }); } // src/util/assertRepoClean.ts async function assertRepoClean(cwd) { if (!await isRepoClean(cwd)) { throw new RadashiError( "Your repository has uncommitted changes. Please commit or stash them before overriding." ); } } // src/fn-override.ts async function addOverride(query, options = {}) { const env = options.env ?? getEnv(options.dir); const { radashiDir } = env; if (!radashiDir) { throw new RadashiError("No upstream repository exists"); } await assertRepoClean(env.root); await pullRadashi(env); let bestMatch; let bestMatchName; await defer(async (onFinish) => { if (options.fromBranch) { await exec("git", ["checkout", options.fromBranch], { cwd: radashiDir, stdio }); onFinish(async () => { await exec("git", ["checkout", "-"], { cwd: radashiDir }); }); } const funcPaths = await getRadashiFuncPaths(env); const { funcPath, funcName } = await queryFuncs(query, funcPaths, { exactMatch: options.exactMatch, message: "Which function do you want to copy?", confirmMessage: 'Is "{funcPath}" the function you want to copy?' }); bestMatch = funcPath; bestMatchName = funcName; let copied = 0; for (const folder of projectFolders) { const fromPath = join3( radashiDir, folder.name, bestMatch + folder.extension ); const outPath = join3( env.overrideDir, folder.name, bestMatch + folder.extension ); const success = await tryCopyFile2(fromPath, outPath); if (success) { copied++; if (folder.name === "src" && options.editor !== false) { await openInEditor(outPath, env, options.editor); } } } copied += (await rewireDependents(bestMatchName, env, funcPaths)).length; log(`${copied} files copied.`); }); const { default: build } = await import("./build-7F3PTR5C.js"); await build({ env }); log(""); await botCommit(`chore: override ${bestMatch}`, { cwd: env.root, add: ["mod.ts", "overrides"] }); } async function tryCopyFile2(src, dst) { debug(`Copying ${cwdRelative(src)} to ${cwdRelative(dst)}`); if (existsSync2(src)) { try { await mkdir2(dirname2(dst), { recursive: true }); await copyFile2(src, dst); return true; } catch { } } return false; } export { assertRepoClean, addOverride };