UNPKG

feature-hub

Version:

Feature-based CLI tool to install backend features easily like auth, cron-job, file-upload, etc.

158 lines (147 loc) 4.54 kB
#! /usr/bin/env node import path from "node:path"; import readline from "node:readline"; import { fileURLToPath } from "url"; import fs from "node:fs"; import fse from "fs-extra"; import { exec } from "child_process"; import { execSync } from "node:child_process"; // Features list const features = [ "auth", "cron-job", "file-upload", "payment", "queue", "redis", "payments", ]; const featurepkgs = { auth: [ "bcryptjs", "mongoose", "jsonwebtoken", "fs-extra", "fastest-validator", "express", "cookie-parser", ], cronJob: ["node-cron", "redis"], queue: ["bullmq", "ioredis"], }; // CLI Arguments const args = process.argv.slice(2); const command = args[0]; const pkgname = args[1]; // Console colors const green = (text) => `\x1b[32m${text}\x1b[0m`; const red = (text) => `\x1b[31m${text}\x1b[0m`; const yellow = (text) => `\x1b[33m${text}\x1b[0m`; // Create readline interface const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); // Helper for logging available features function showAvailableFeatures() { console.log(yellow("\nAvailable Features:")); features.forEach((f) => console.log(` - ${f}`)); } // Start CLI logic if (command === "install" || command === "i") { if (!pkgname || !features.includes(pkgname)) { console.log(red("❌ Invalid or missing package name!\n")); showAvailableFeatures(); rl.close(); process.exit(1); } rl.question( green( `\n✅ Where do you want to install "${pkgname}"? Provide the path:\n> ` ), (inputPath) => { rl.close(); // Resolve paths const projectPath = path.resolve(process.cwd(), inputPath); const targetPath = path.join(projectPath, `feature-hub/${pkgname}`); editEnvfile(projectPath, pkgname); const __dirname = path.dirname(fileURLToPath(import.meta.url)); const sourcePath = path.join(__dirname, "../features", pkgname); // Check if already exists if (fs.existsSync(targetPath)) { console.log(red("\n❌ Feature already exists at target location!\n")); process.exit(1); } // Copy folder try { fse.copySync(sourcePath, targetPath, { overwrite: true }); editPackageJson(projectPath, featurepkgs[pkgname]); console.log( green(`\n✅ Successfully installed "${pkgname}" at ${targetPath}`) ); } catch (err) { console.log(red("❌ Failed to copy feature folder: "), err.message); } process.exit(0); } ); } else { console.log(red("❌ Invalid command!\n")); console.log(yellow("Usage:")); console.log(" feature-hub install <feature>"); console.log(" feature-hub i <feature>"); showAvailableFeatures(); rl.close(); } function editEnvfile(projectpath, pkgname) { const envfileExists = fs.existsSync(path.join(projectpath, ".env")); if (!envfileExists) { fs.writeFileSync(path.join(projectpath, ".env"), "", "utf-8"); } switch (pkgname) { case "auth": aditenv(projectpath, { JWT_SECRET: "PleaseChangeMe" }); break; case "queue": aditenv(projectpath,{ REDIS_HOST: "redis://localhost", REDIS_PORT: 6379 ,password:"" }); break; case "cron-job": aditenv(projectpath,{ key: "CRON_JOB_URL", value: "redis://localhost:6379" }); break; } } function editPackageJson(projectPath, pkgname = []) { console.log(pkgname.join(" ")); const packageJsonExists = fs.existsSync( path.join(projectPath, "package.json") ); if (packageJsonExists) { const packageJsonContent = fs.readFileSync( path.join(projectPath, "package.json"), "utf-8" ); const packageJson = JSON.parse(packageJsonContent); let packageManager = packageJson.packageManager || "npm"; if (packageManager.includes("pnpm")) { execSync(`pnpm install ${pkgname.join(" ")}`); console.log("required packages installed by pnpm"); } else if (packageManager.includes("yarn")) { execSync(`yarn add ${pkgname.join(" ")}`); console.log("required packages installed by yarn"); } else if (packageManager.includes("npm")) { execSync(`npm install ${pkgname.join(" ")}`); console.log("required packages installed by npm"); } } else { console.log("package.json not found"); } } function aditenv(projectpath, keyValue = {}) { for (const [key, value] of Object.entries(keyValue)) { fs.appendFileSync( path.join(projectpath, ".env"), `${key}=${value}\n`, "utf-8" ); } }