blaze-install
Version:
A new package manager
272 lines (264 loc) • 6.76 kB
JavaScript
const { main, printHelp } = require("../lib/index");
const args = process.argv.slice(2);
const command = args[0];
// Add support for --version and -v flags
if (args.includes('--version') || args.includes('-v')) {
const { version } = require('../package.json');
console.log(`blaze-install version ${version}`);
process.exit(0);
}
if (command === "--help" || command === "help") {
printHelp();
process.exit(0);
}
// If no command, default to install
if (!command) {
main(["install", ...args]);
return;
}
// Supported commands (add more as you implement them)
const supported = [
"init",
"install",
"uninstall",
"update",
"audit",
"list",
"clean",
"outdated",
"info",
"--interactive",
"publish",
"version",
"audit fix",
"run",
"link",
"unlink",
"graph",
"upgrade",
"doctor",
"prefetch",
"watch",
"fix",
"clean-github-specs",
];
if (supported.includes(command)) {
if (command === "watch") {
// --- blaze watch: auto-install missing packages on code change ---
const chokidar = require("chokidar");
const fs = require("fs");
const { execSync } = require("child_process");
const glob = require("glob");
const watchedExts = [
".js",
".ts",
".jsx",
".tsx",
".mjs",
".cjs",
".mts",
".cts",
".json",
".vue",
];
const ignored =
/node_modules|\.git|plugins|\.blaze|dist|build|out|coverage|\.next|\.cache|\.vscode/;
const pkgJson = fs.existsSync("package.json")
? JSON.parse(fs.readFileSync("package.json", "utf8"))
: {};
let installed = new Set([
...Object.keys(pkgJson.dependencies || {}),
...Object.keys(pkgJson.devDependencies || {}),
]);
let pending = new Set();
let batchTimeout = null;
// Node.js core modules to skip
const nodeCoreModules = new Set([
"assert",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"dns",
"domain",
"events",
"fs",
"http",
"https",
"module",
"net",
"os",
"path",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"string_decoder",
"timers",
"tls",
"tty",
"url",
"util",
"v8",
"vm",
"zlib",
"inspector",
"async_hooks",
"worker_threads",
"trace_events",
"http2",
"diagnostics_channel",
"wasi",
"node:assert",
"node:buffer",
"node:child_process",
"node:cluster",
"node:console",
"node:constants",
"node:crypto",
"node:dgram",
"node:dns",
"node:domain",
"node:events",
"node:fs",
"node:http",
"node:https",
"node:module",
"node:net",
"node:os",
"node:path",
"node:perf_hooks",
"node:process",
"node:punycode",
"node:querystring",
"node:readline",
"node:repl",
"node:stream",
"node:string_decoder",
"node:timers",
"node:tls",
"node:tty",
"node:url",
"node:util",
"node:v8",
"node:vm",
"node:zlib",
"node:inspector",
"node:async_hooks",
"node:worker_threads",
"node:trace_events",
"node:http2",
"node:diagnostics_channel",
"node:wasi",
]);
function extractPackages(code) {
const requireRegex = /require\(['"]([^'"/]+)['"]\)/g;
const importRegex = /import\s+.*?from\s+['"]([^'"/]+)['"]/g;
const pkgs = new Set();
let m;
while ((m = requireRegex.exec(code))) pkgs.add(m[1]);
while ((m = importRegex.exec(code))) pkgs.add(m[1]);
// Filter out relative imports and Node core modules
return Array.from(pkgs).filter(
(p) =>
!p.startsWith(".") && !p.startsWith("/") && !nodeCoreModules.has(p),
);
}
function batchInstall() {
if (pending.size === 0) return;
const pkgs = Array.from(pending).filter((pkg) => !installed.has(pkg));
if (pkgs.length === 0) return;
console.log(
`[blaze-watch] Installing missing packages: ${pkgs.join(", ")}`,
);
try {
execSync(`blaze install ${pkgs.join(" ")}`, {
stdio: "inherit",
});
pkgs.forEach((pkg) => installed.add(pkg));
} catch (e) {
console.warn(
`[blaze-watch] Failed to install some packages:`,
e.message,
);
}
pending.clear();
}
// --- Initial scan for missing packages ---
const globPattern = `**/*.{${watchedExts.map((e) => e.replace(".", "")).join(",")}}`;
const files = glob.sync(globPattern, {
ignore: [
"**/node_modules/**",
"**/.git/**",
"**/plugins/**",
"**/.blaze/**",
"**/dist/**",
"**/build/**",
"**/out/**",
"**/coverage/**",
"**/.next/**",
"**/.cache/**",
"**/.vscode/**",
],
});
const allPkgs = new Set();
for (const file of files) {
try {
const code = fs.readFileSync(file, "utf8");
extractPackages(code).forEach((pkg) => allPkgs.add(pkg));
} catch {}
}
const missing = Array.from(allPkgs).filter((pkg) => !installed.has(pkg));
if (missing.length) {
console.log(
`[blaze-watch] Detected missing packages on startup: ${missing.join(", ")}`,
);
try {
execSync(`blaze install ${missing.join(" ")}`, {
stdio: "inherit",
});
missing.forEach((pkg) => installed.add(pkg));
} catch (e) {
console.warn(
`[blaze-watch] Failed to install some packages on startup:`,
e.message,
);
}
}
// --- Start watcher as before ---
chokidar.watch(".", { ignored, persistent: true }).on("change", (file) => {
if (!watchedExts.some((ext) => file.endsWith(ext))) return;
console.log(`[blaze-watch] Detected change in: ${file}`);
const code = fs.readFileSync(file, "utf8");
const pkgs = extractPackages(code);
pkgs.forEach((pkg) => {
if (!installed.has(pkg)) pending.add(pkg);
});
if (batchTimeout) clearTimeout(batchTimeout);
batchTimeout = setTimeout(batchInstall, 1000); // batch within 1s window
});
console.log(
"[blaze-watch] Watching for new imports/requires in all supported file types...",
);
return;
}
(async () => {
try {
await main(args);
} catch (err) {
console.error(err);
process.exit(1);
}
})();
} else {
console.log("Unknown command:", command);
printHelp();
process.exit(1);
}