a meowing, typesafe interaction router for discord.js
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176import { readFileSync, writeFileSync } from "node:fs";import { join } from "node:path";import { execSync } from "node:child_process";
const ROOT = join(import.meta.dir, "..");const PKGS_DIR = join(ROOT, "pkgs");
const BUILD_ORDER = [ "types", "collection", "permissions", "builders", "gateway", "ratelimit", "rest", "cache", "structures", "router", "client",] as const;
type PkgShort = (typeof BUILD_ORDER)[number];type BumpType = "patch" | "minor" | "major";
interface Pkg { name: string; short: PkgShort; version: string; deps: string[]; peers: string[]; path: string;}
const isDryRun = process.argv.includes("--dry-run") || process.argv.includes("-d");
function git(cmd: string): string { return execSync(`git ${cmd}`, { cwd: ROOT, encoding: "utf-8" }).trim();}
function run(cmd: string, cwd = ROOT, prefix = "\t") { if (isDryRun) { console.log(`${prefix} $ ${cmd}`); return; } try { execSync(cmd, { cwd, stdio: "inherit" }); } catch { rollback(); }}
function rollback() { console.error("\nfailed. reverting changes..."); git("checkout -- pkgs/*/package.json"); process.exit(1);}
function loadPackages(): Map<PkgShort, Pkg> { const pkgs = new Map<PkgShort, Pkg>(); for (const short of BUILD_ORDER) { const pkgPath = join(PKGS_DIR, short, "package.json"); const raw = JSON.parse(readFileSync(pkgPath, "utf-8"));
const deps = Object.keys(raw.dependencies ?? {}) .filter((d) => d.startsWith("@purrkit/")) .map((d) => d.replace("@purrkit/", ""));
const peers = Object.keys(raw.peerDependencies ?? {}) .filter((d) => d.startsWith("@purrkit/")) .map((d) => d.replace("@purrkit/", ""));
pkgs.set(short, { name: raw.name, short, version: raw.version, deps, peers, path: pkgPath }); } return pkgs;}
function bumpVersion(version: string, type: BumpType): string { const [major, minor, patch] = version.split(".").map(Number); if (type === "major") return `${major! + 1}.0.0`; if (type === "minor") return `${major}.${minor! + 1}.0`; if (type === "patch") return `${major}.${minor}.${patch! + 1}`; throw new Error(`invalid bump type: ${type}`);}
function findAffected(pkgs: Map<PkgShort, Pkg>, target: PkgShort): PkgShort[] { const affectedSet = new Set<PkgShort>([target]);
function walk(current: string) { for (const [short, pkg] of pkgs) { if (affectedSet.has(short)) continue; if (pkg.deps.includes(current) || pkg.peers.includes(current)) { affectedSet.add(short); walk(short); } } }
walk(target); return BUILD_ORDER.filter((short) => affectedSet.has(short));}
function main() { const [targetShort, bumpType] = process.argv.slice(2).filter((arg) => !arg.startsWith("-")) as [ PkgShort, BumpType, ];
const validBumpTypes: BumpType[] = ["patch", "minor", "major"];
if (!targetShort || !validBumpTypes.includes(bumpType)) { console.error("usage: bun run scripts/publish.ts <package> <patch|minor|major> [--dry-run]"); console.error(" e.g: bun run scripts/publish.ts rest patch --dry-run"); process.exit(1); }
if (!BUILD_ORDER.includes(targetShort)) { console.error(`unknown package: ${targetShort}`); console.error(`available: ${BUILD_ORDER.join(", ")}`); process.exit(1); }
if (!isDryRun && git("status --porcelain pkgs")) { console.error("work tree is dirty. commit or stash changes first."); process.exit(1); }
const pkgs = loadPackages(); const target = pkgs.get(targetShort)!; const affected = findAffected(pkgs, targetShort);
console.log( `bumping @purrkit/${targetShort} (${target.version} -> ${bumpVersion(target.version, bumpType)})${isDryRun ? " [DRY RUN]" : ""}`, ); console.log(`affected: ${affected.map((s) => `@purrkit/${s}`).join(" -> ")}`);
for (const short of affected) { const pkg = pkgs.get(short)!; const oldVersion = pkg.version; const newVersion = bumpVersion(oldVersion, bumpType); pkg.version = newVersion;
if (!isDryRun) { const raw = JSON.parse(readFileSync(pkg.path, "utf-8")); raw.version = newVersion; writeFileSync(pkg.path, JSON.stringify(raw, null, "\t") + "\n"); } console.log(`\t${pkg.name}: ${oldVersion} -> ${newVersion}`); }
console.log("\nbuilding..."); for (const short of affected) { run(`bun run build:${short}`); }
console.log("\npublishing..."); for (const short of affected) { const pkg = pkgs.get(short)!; console.log(`\t${pkg.name}@${pkg.version}`); run("bun publish --access public", join(PKGS_DIR, short), "\t "); }
console.log("\ncommitting & tagging..."); const commitMsg = `release: ${affected.map((s) => `@purrkit/${s}@${pkgs.get(s)!.version}`).join(", ")}`; run("git add pkgs/*/package.json"); run(`git commit -m "${commitMsg}"`);
for (const short of affected) { const pkg = pkgs.get(short)!; run(`git tag -a ${pkg.name}@${pkg.version} -m "${pkg.name}@${pkg.version}"`); }
console.log("\ndone.");}
main();