UNPKG

create-kyrix-app

Version:

A CLI tool to create a Kyrix app.

284 lines (250 loc) 8.44 kB
#!/usr/bin/env node import degit from "degit"; import path from "path"; import fs from "fs"; import { confirm, select, isCancel } from "@clack/prompts"; import ora from "ora"; // Import ora for spinner import chalk from "chalk"; // Import configuration files import { setupPrisma } from "./setup/prismaConfig.js"; import { setupDrizzle } from "./setup/drizzleConfig.js"; import { setupMongoose } from "./setup/mongooseConfig.js"; import { setupDocker } from "./setup/dockerConfig.js"; import { setupDependencies } from "./setup/dependencies/config.js"; import { checkPackageManagers } from "./scripts/managerFinder.js"; import { intro } from "./utils/customIntro.js"; import { cleanUpOnExit } from "./utils/exitProcess.js"; import { setupTailwind } from "./setup/tailwindConfig.js"; import { addTailwindDependencies } from "./setup/dependencies/addTailwindDependencies.js"; import { setUpKyrix } from "./setup/dependencies/kyrixDependencies.js"; // Get project name from command-line arguments const args = process.argv.slice(2); // Skip "node" and script name const projectName = args[0] || "kyrix-app"; // Default to "kyrix-app" if no name provided (async () => { // Define the Kyrix repo URL const repoUrl = "https://github.com/evolvedev-inc/kyrix/templates/kyrix-react-router"; // Check for available package managers const availableManagers = checkPackageManagers(); // Determine the target directory let targetPath; if (projectName === "." || projectName === "./") { // Clone into the current directory targetPath = process.cwd(); } else { // Create a new directory for the project targetPath = path.join(process.cwd(), projectName); // Check if the folder already exists if (fs.existsSync(targetPath)) { console.log( chalk.red( `The folder ${chalk.bold( projectName )} already exists. Please use another name or delete the existing folder.` ) ); process.exit(1); } } // Display an custom intro message using Clack intro("Welcome to Kyrix App Setup"); // Prompt user for package manager selection let packageManagerChoice; try { packageManagerChoice = await select({ message: "Choose your package manager:", options: availableManagers.map((manager) => ({ label: manager, value: manager, })), }); if (isCancel(packageManagerChoice)) { console.log("Operation cancelled by user."); cleanUpOnExit(targetPath); process.exit(0); } } catch (err) { console.error(chalk.red("Prompt error: "), err); cleanUpOnExit(targetPath); process.exit(1); } // Prompt if the user wants to tailwind config let tailwind; try { tailwind = await confirm({ message: chalk.cyan( "Do you want to include Tailwind CSS in your project?" ), }); if (isCancel(tailwind)) { console.log("Operation cancelled by user."); cleanUpOnExit(targetPath); process.exit(0); } } catch (err) { console.error(chalk.red("Prompt error: "), err); cleanUpOnExit(targetPath); process.exit(1); } // Prompt if the user wants to connect a database let connectDb; try { connectDb = await confirm({ message: chalk.cyan( "Do you want to connect the Kyrix app with a database?" ), }); if (isCancel(connectDb)) { console.log("Operation cancelled by user."); cleanUpOnExit(targetPath); process.exit(0); } } catch (err) { console.error(chalk.red("Prompt error: "), err); cleanUpOnExit(targetPath); process.exit(1); } let dbChoice, ormChoice; if (connectDb) { // Ask for database selection try { dbChoice = await select({ message: chalk.cyan("Choose your database connection:"), options: [ { label: chalk.bold.magenta("1. PostgreSQL"), value: "postgresql" }, { label: chalk.bold.magenta("2. MySQL"), value: "mysql" }, { label: chalk.bold.magenta("3. MongoDB"), value: "mongodb" }, ], }); if (isCancel(dbChoice)) { console.log("Operation cancelled by user."); cleanUpOnExit(targetPath); process.exit(0); } // For PostgreSQL and MySQL, ask if the user wants an ORM if (dbChoice === "postgresql" || dbChoice === "mysql") { ormChoice = await select({ message: chalk.cyan(`Choose an ORM for ${dbChoice}:`), options: [ { label: chalk.bold.magenta("1. Prisma"), value: "prisma" }, { label: chalk.bold.magenta("2. Drizzle"), value: "drizzle" }, ], }); if (isCancel(ormChoice)) { console.log("Operation cancelled by user."); cleanUpOnExit(targetPath); process.exit(0); } } } catch (err) { console.error(chalk.red("Prompt error: "), err); cleanUpOnExit(targetPath); process.exit(1); } } // Ask if the user wants to use Docker let useDocker; try { useDocker = await confirm({ message: chalk.cyan("Do you want to use Docker?"), }); if (isCancel(useDocker)) { console.log("Operation cancelled by user."); cleanUpOnExit(targetPath); process.exit(0); } } catch (err) { console.error(chalk.red("Prompt error: "), err); cleanUpOnExit(targetPath); process.exit(1); } // Set up spinner for cloning const spinner = ora({ text: projectName === "." || projectName === "./" ? "Creating the Kyrix app in current directory..." : `Creating the Kyrix app in ${chalk.green(projectName)}...`, color: "cyan", }).start(); // repo config const emitter = degit(repoUrl, { cache: false, force: true, verbose: true, }); try { // Perform the Git clone operation await emitter.clone(path.resolve(targetPath)); // Remove the .git folder if it exists const gitFolderPath = path.join(targetPath, ".git"); if (fs.existsSync(gitFolderPath)) { fs.rmSync(gitFolderPath, { recursive: true }); } if (packageManagerChoice !== "pnpm") { const pnpmWorkspacePath = path.join(targetPath, "pnpm-workspace.yaml"); if (fs.existsSync(pnpmWorkspacePath)) { fs.rmSync(pnpmWorkspacePath, { recursive: true }); } } spinner.succeed( `Kyrix app created successfully ${ projectName === "." || projectName === "./" ? "in current directory!" : `in ${chalk.green(projectName)}!` }` ); await setUpKyrix(targetPath, packageManagerChoice); // Now set up the tailwind css config if (tailwind) { setupTailwind(targetPath); addTailwindDependencies(targetPath); } // Now set up the database connection based on user config if (connectDb) { if (dbChoice === "postgresql") { if (ormChoice === "prisma") { setupPrisma(targetPath, chalk, dbChoice); } else if (ormChoice === "drizzle") { setupDrizzle(targetPath, chalk, dbChoice); } } else if (dbChoice === "mysql") { if (ormChoice === "prisma") { setupPrisma(targetPath, chalk, dbChoice); } else if (ormChoice === "drizzle") { setupDrizzle(targetPath, chalk, dbChoice); } } else if (dbChoice === "mongodb") { setupMongoose(targetPath, chalk); } if (useDocker) { setupDocker(targetPath, dbChoice, chalk); } // Dependencies setupDependencies(targetPath, ormChoice, dbChoice); // Dynamic install command const installCommand = { npm: "npm install", pnpm: "pnpm install", yarn: "yarn install", bun: "bun add", }[packageManagerChoice]; if (projectName === "." || projectName === "./") { console.log( chalk.bgMagenta.bold.white( `Run ${installCommand} in the current directory to install the new dependencies.` ) ); } else { console.log( chalk.bgCyan.bold.white( `Run ${installCommand} in the ${projectName} directory to install the new dependencies.` ) ); } } } catch (err) { spinner.fail("Failed to create Kyrix app."); console.error(chalk.red("Failed to create Kyrix app: "), err); cleanUpOnExit(targetPath); // Cleanup on error process.exit(1); } })();