|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +/** |
| 4 | + * |
| 5 | +export __MINIMUMRELEASEAGE=@koa/router |
| 6 | +export __MINIMUMRELEASEAGE_MODE=dev|prod |
| 7 | +NODE_OPTIONS= pnpm view "${__MINIMUMRELEASEAGE}" name time --json | NODE_OPTIONS= node bash/pnpm/minimumReleaseAge.ts ${__MINIMUMRELEASEAGE_MODE} |
| 8 | +
|
| 9 | + * to find version which satisfies |
| 10 | + * minimumReleaseAge: 43200 from pnpm-workspace.yaml |
| 11 | + * |
| 12 | + * Assuming file pnpm-workspace.yaml exist with content |
| 13 | +
|
| 14 | +vvvvvvv |
| 15 | +cat <<EEE > pnpm-workspace.yaml |
| 16 | +# 30 days - run pnpm config get minimumReleaseAge to see value |
| 17 | +minimumReleaseAge: 43200 |
| 18 | +# to see how to find valid version of given library see bash/pnpm/minimumReleaseAge.ts |
| 19 | +
|
| 20 | +EEE |
| 21 | +^^^^^^^ |
| 22 | +
|
| 23 | + */ |
| 24 | + |
| 25 | +type TimeMap = Record<string, string>; |
| 26 | + |
| 27 | +const MIN_AGE_DAYS = Number(process.env.MIN_AGE_DAYS ?? 30); |
| 28 | +const MIN_AGE_MS = MIN_AGE_DAYS * 24 * 60 * 60 * 1000; |
| 29 | + |
| 30 | +const mode = process.argv[2]; |
| 31 | +if (!mode || (mode !== "dev" && mode !== "prod")) { |
| 32 | + throw new Error("Parameter 'dev' or 'prod' is required as the first argument."); |
| 33 | +} |
| 34 | +let pkgName = process.argv[3] || "[library]"; |
| 35 | +const installCmd = mode === "dev" ? "pnpm install -D" : "pnpm install"; |
| 36 | + |
| 37 | +function readStdin(): Promise<string> { |
| 38 | + return new Promise((resolve, reject) => { |
| 39 | + let data = ""; |
| 40 | + |
| 41 | + process.stdin.setEncoding("utf8"); |
| 42 | + |
| 43 | + process.stdin.on("data", (chunk) => { |
| 44 | + data += chunk; |
| 45 | + }); |
| 46 | + |
| 47 | + process.stdin.on("end", () => resolve(data)); |
| 48 | + process.stdin.on("error", reject); |
| 49 | + }); |
| 50 | +} |
| 51 | + |
| 52 | +function error(msg: string): never { |
| 53 | + console.error(`❌ ${msg}`); |
| 54 | + process.exit(1); |
| 55 | +} |
| 56 | + |
| 57 | +(async () => { |
| 58 | + const raw = await readStdin(); |
| 59 | + |
| 60 | + if (!raw || raw.trim().length === 0) { |
| 61 | + error("No input provided. Expected: pnpm view <pkg> name time --json | node minimumReleaseAge.ts <dev|prod>"); |
| 62 | + } |
| 63 | + |
| 64 | + let data: TimeMap; |
| 65 | + |
| 66 | + try { |
| 67 | + const parsed = JSON.parse(raw); |
| 68 | + if (parsed && typeof parsed === "object") { |
| 69 | + if (parsed.name && parsed.time && typeof parsed.time === "object") { |
| 70 | + pkgName = parsed.name; |
| 71 | + data = parsed.time; |
| 72 | + } else { |
| 73 | + data = parsed; |
| 74 | + } |
| 75 | + } else { |
| 76 | + throw new Error("Invalid structure"); |
| 77 | + } |
| 78 | + } catch (e) { |
| 79 | + error("Invalid JSON input (expected pnpm --json output)"); |
| 80 | + } |
| 81 | + |
| 82 | + const now = Date.now(); |
| 83 | + |
| 84 | + const rows = Object.entries(data).map(([version, time]) => { |
| 85 | + const t = new Date(time).getTime(); |
| 86 | + const age = now - t; |
| 87 | + |
| 88 | + return { |
| 89 | + version, |
| 90 | + time, |
| 91 | + ageDays: +(age / 86400000).toFixed(2), |
| 92 | + ok: age >= MIN_AGE_MS, |
| 93 | + }; |
| 94 | + }); |
| 95 | + |
| 96 | + rows.sort((a, b) => new Date(b.time).getTime() - new Date(a.time).getTime()); |
| 97 | + |
| 98 | + const okRows = rows.filter((r) => r.ok); |
| 99 | + |
| 100 | + console.log(`\nMinimum age: ${MIN_AGE_DAYS} days\n`); |
| 101 | + console.log(`Total versions: ${rows.length}`); |
| 102 | + console.log(`Valid versions: ${okRows.length}\n`); |
| 103 | + |
| 104 | + for (const r of rows) { |
| 105 | + const mark = r.ok ? "✅" : "❌"; |
| 106 | + const versionStr = r.version.padEnd(20); |
| 107 | + const ageStr = `${r.ageDays}d`.padStart(10); |
| 108 | + const cmdStr = r.ok ? `pnpm remove ${pkgName} && ${installCmd} ${pkgName}@${r.version}` : ""; |
| 109 | + console.log(`${mark} ${versionStr} | ${ageStr} | ${r.time} | ${cmdStr}`); |
| 110 | + } |
| 111 | + |
| 112 | + const best = okRows[0]; |
| 113 | + |
| 114 | + if (best) { |
| 115 | + console.log(`\n👉 Best matching version: ${best.version}`); |
| 116 | + } else { |
| 117 | + console.log("\n⚠️ No versions satisfy minimumReleaseAge"); |
| 118 | + } |
| 119 | +})(); |
0 commit comments