This commit is contained in:
s.esmaeili
2026-10-04 20:11:09 +03:30
parent b5b3cd8bef
commit 6ae48d417d
7 changed files with 977 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env node
// For each npm package, prints its four newest major lines: first release,
// latest version and when that latest version was published. A line with no
// release for a long time has probably stopped receiving patches.
//
// Backs the version table in docs/GO-LIVE-PLAN.md §4. Re-run it before acting
// on that table — the numbers there are only true for the day they were taken.
//
// node scripts/check-majors.mjs # the packages the plan tracks
// node scripts/check-majors.mjs vite pinia # any packages
//
// Goes through the npm CLI rather than fetch() so the machine's registry or
// mirror settings (.npmrc) apply.
import { execSync } from 'node:child_process';
const TRACKED = [
'vue', 'vite', '@vitejs/plugin-vue', 'vite-plugin-pwa', 'vue-router', 'pinia',
'typescript', 'vue-tsc', 'tailwindcss', 'ant-design-vue', 'vant', '@vueuse/core',
'@nestjs/core', 'prisma',
];
// Package names only — they are interpolated into a shell command.
const PACKAGE_NAME = /^(@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*$/i;
const STALE_AFTER_DAYS = 180;
const pkgs = process.argv.length > 2 ? process.argv.slice(2) : TRACKED;
const now = Date.now();
for (const pkg of pkgs) {
if (!PACKAGE_NAME.test(pkg)) {
console.log(`\n${pkg}: not a package name, skipped`);
continue;
}
let published;
try {
published = JSON.parse(
execSync(`npm view ${pkg} time --json`, {
encoding: 'utf8',
timeout: 60_000,
stdio: ['ignore', 'pipe', 'ignore'],
}),
);
} catch {
console.log(`\n${pkg}: npm view failed`);
continue;
}
const lines = new Map();
for (const [version, date] of Object.entries(published)) {
// Stable releases only; this also drops the `created` / `modified` keys.
if (!/^\d+\.\d+\.\d+$/.test(version)) continue;
const major = Number(version.split('.')[0]);
const line = lines.get(major) ?? { firstVersion: version, first: date, lastVersion: version, last: date };
if (date < line.first) Object.assign(line, { firstVersion: version, first: date });
if (date > line.last) Object.assign(line, { lastVersion: version, last: date });
lines.set(major, line);
}
console.log(`\n${pkg}`);
const newestFirst = [...lines].sort(([a], [b]) => b - a).slice(0, 4);
for (const [major, line] of newestFirst) {
const idleDays = Math.floor((now - Date.parse(line.last)) / 86_400_000);
const stale = idleDays > STALE_AFTER_DAYS ? ` <- no release for ${idleDays} days` : '';
console.log(
` v${String(major).padEnd(3)} first ${line.firstVersion.padEnd(9)} ${line.first.slice(0, 10)}` +
` latest ${line.lastVersion.padEnd(9)} ${line.last.slice(0, 10)}${stale}`,
);
}
}