UNPKG

archgenie

Version:

A powerful Node.js CLI tool to quickly scaffold project folder structures based on popular software architecture patterns.

449 lines (423 loc) 8.47 kB
#!/usr/bin/env node const fs = require("fs").promises; const path = require("path"); const readline = require("readline"); const { exec } = require("child_process"); // Created by Praveen KR // https://www.linkedin.com/in/mepraveenkr/ // https://github.com/frontenddeveloperpraveen const CLI_FILE = ".cli"; const VERSION = "1.1.3"; const file = { "--mvc": [ "models", "views", "controllers", "services", "middlewares", "config", "utils", "tests", "docs", ], "--mvp": [ "models", "views", "presenters", "services", "middlewares", "config", "utils", "tests", "docs", ], "--mvvm": [ "models", "views", "viewmodels", "services", "middlewares", "config", "utils", "tests", "docs", ], "--pac": [ "presentation", "abstraction", "control", "services", "middlewares", "config", "utils", "tests", "docs", ], "--hmvc": [ "modules", "models", "views", "controllers", "services", "middlewares", "config", "utils", "tests", "docs", ], "--layered": [ "presentation_layer", "application_layer", "business_layer", "persistence_layer", "database", "middlewares", "config", "utils", "tests", "docs", ], "--monolithic": [ "controllers", "models", "views", "services", "middlewares", "config", "utils", "tests", "docs", ], "--microservices": [ "service_A", "service_B", "service_C", "shared_libs", "gateway", "middlewares", "config", "utils", "tests", "docs", ], "--soa": [ "services", "service_bus", "adapters", "middlewares", "config", "utils", "tests", "docs", ], "--serverless": [ "functions", "triggers", "middlewares", "config", "utils", "tests", "docs", ], "--clean": [ "entities", "use_cases", "interfaces", "frameworks", "middlewares", "config", "utils", "tests", "docs", ], "--hexagonal": [ "core", "ports", "adapters", "middlewares", "config", "utils", "tests", "docs", ], "--onion": [ "domain", "application", "infrastructure", "interfaces", "middlewares", "config", "utils", "tests", "docs", ], "--rest": [ "routes", "controllers", "models", "services", "middlewares", "config", "utils", "tests", "docs", ], "--graphql": [ "schemas", "resolvers", "models", "services", "middlewares", "config", "utils", "tests", "docs", ], "--grpc": [ "proto_files", "services", "handlers", "middlewares", "config", "utils", "tests", "docs", ], "--event_driven": [ "event_producers", "event_consumers", "event_bus", "middlewares", "config", "utils", "tests", "docs", ], "--cqrs": [ "commands", "queries", "models", "services", "middlewares", "config", "utils", "tests", "docs", ], "--pub_sub": [ "publishers", "subscribers", "message_broker", "middlewares", "config", "utils", "tests", "docs", ], "--client_server": [ "client", "server", "middlewares", "config", "utils", "tests", "docs", ], "--p2p": [ "nodes", "peer_connections", "middlewares", "config", "utils", "tests", "docs", ], "--master_slave": [ "master", "slaves", "middlewares", "config", "utils", "tests", "docs", ], "--leader_follower": [ "leader", "followers", "middlewares", "config", "utils", "tests", "docs", ], "--load_balanced_cluster": [ "load_balancer", "nodes", "middlewares", "config", "utils", "tests", "docs", ], "--blackboard": [ "blackboard", "knowledge_sources", "controllers", "middlewares", "config", "utils", "tests", "docs", ], "--pipes_filters": [ "pipes", "filters", "middlewares", "config", "utils", "tests", "docs", ], "--microkernel": [ "core_system", "plugins", "middlewares", "config", "utils", "tests", "docs", ], "--service_mesh": [ "control_plane", "data_plane", "middlewares", "config", "utils", "tests", "docs", ], "--reactive": [ "event_streams", "reactive_components", "middlewares", "config", "utils", "tests", "docs", ], }; function promptUser(question) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => rl.question(question, (ans) => { rl.close(); resolve(ans.trim().toLowerCase()); }) ); } async function getCurrentArch() { try { const data = await fs.readFile(CLI_FILE, "utf8"); return data.trim(); } catch { return null; // No file yet } } async function setCurrentArch(arch) { await fs.writeFile(CLI_FILE, arch); } async function deleteAllExceptNodeModulesAndCli() { const items = await fs.readdir(process.cwd()); for (const item of items) { if (item === "node_modules" || item === CLI_FILE) continue; await fs.rm(path.join(process.cwd(), item), { recursive: true, force: true, }); } } async function backupCurrentArch(currentArch) { const backupDir = `backup-${currentArch}`; await fs.mkdir(backupDir, { recursive: true }); const items = await fs.readdir(process.cwd()); for (const item of items) { if ( item === "node_modules" || item === CLI_FILE || item === backupDir // prevent moving backup into itself ) continue; await fs.rename(path.join(process.cwd(), item), path.join(backupDir, item)); } } async function createFolder(folderList) { const files_name = [".gitignore", "server.js"]; for (const filename of files_name) { const f = await fs.open(filename, "a"); if (filename === ".gitignore") await f.write("node_modules\n.cli\n"); await f.close(); } const commands = ["git init", "npm init -y", "npm i express nodemon"]; for (const cmd of commands) { exec(cmd, (error, stdout, stderr) => { if (error) return console.error(`Error: ${error.message}`); if (stderr) return console.error(`Stderr: ${stderr}`); console.log(`${cmd}:\n${stdout}`); }); } for (const folder of folderList) { try { await fs.mkdir(folder, { recursive: true }); console.log(`${folder} created successfully!`); } catch (err) { console.error("Error creating folder:", err); } } } function showHelp() { console.log(` Usage: cli-tool <architecture-flag> Available Flags: ${Object.keys(file).join("\n ")} --help --version `); } (async () => { const args = process.argv[2]; if (!args || args === "--help") { showHelp(); process.exit(0); } if (args === "--version") { console.log(`Version: ${VERSION}`); process.exit(0); } if (!file[args]) { console.error("Invalid architecture flag. Use --help to see options."); process.exit(1); } const currentArch = await getCurrentArch(); if (currentArch && currentArch !== args) { console.log(`Detected previous architecture: ${currentArch}`); const choice = await promptUser( "Do you want to delete all files or take a backup? (delete/backup): " ); if (choice === "delete") { await deleteAllExceptNodeModulesAndCli(); console.log("All files deleted."); } else if (choice === "backup") { await backupCurrentArch(currentArch); console.log(`Backup created in folder: backup-${currentArch}`); } else { console.log("Invalid choice. Exiting."); process.exit(1); } } await createFolder(file[args]); await setCurrentArch(args); })();