diff --git a/biome.json b/biome.json index 2eb0751..3c65d00 100644 --- a/biome.json +++ b/biome.json @@ -7,7 +7,8 @@ }, "files": { "ignoreUnknown": false, - "ignore": [] + "ignore": [], + "include": ["**/*.ts"] }, "formatter": { "enabled": true, diff --git a/bun.lock b/bun.lock index acd5962..13649b3 100644 --- a/bun.lock +++ b/bun.lock @@ -4,11 +4,12 @@ "": { "name": "create-better-t", "dependencies": { - "@drizzle-team/brocli": "^0.11.0", "@inquirer/prompts": "^7.3.1", "chalk": "^5.3.0", + "commander": "^13.1.0", "execa": "^8.0.1", "fs-extra": "^11.2.0", + "gradient-string": "^3.0.0", "ora": "^7.0.1", }, "devDependencies": { @@ -40,8 +41,6 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], - "@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q=="], @@ -184,6 +183,8 @@ "@types/through": ["@types/through@0.0.33", "", { "dependencies": { "@types/node": "*" } }, "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ=="], + "@types/tinycolor2": ["@types/tinycolor2@1.4.6", "", {}, "sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw=="], + "@vitest/expect": ["@vitest/expect@1.6.1", "", { "dependencies": { "@vitest/spy": "1.6.1", "@vitest/utils": "1.6.1", "chai": "^4.3.10" } }, "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog=="], "@vitest/runner": ["@vitest/runner@1.6.1", "", { "dependencies": { "@vitest/utils": "1.6.1", "p-limit": "^5.0.0", "pathe": "^1.1.1" } }, "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA=="], @@ -242,7 +243,7 @@ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + "commander": ["commander@13.1.0", "", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="], "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], @@ -284,6 +285,8 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "gradient-string": ["gradient-string@3.0.0", "", { "dependencies": { "chalk": "^5.3.0", "tinygradient": "^1.1.5" } }, "sha512-frdKI4Qi8Ihp4C6wZNB565de/THpIaw3DjP5ku87M+N9rNSGmPTjfkq61SdRXB7eCaL8O1hkKDvf6CDMtOzIAg=="], + "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], @@ -442,10 +445,14 @@ "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], + "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], "tinyglobby": ["tinyglobby@0.2.10", "", { "dependencies": { "fdir": "^6.4.2", "picomatch": "^4.0.2" } }, "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew=="], + "tinygradient": ["tinygradient@1.1.5", "", { "dependencies": { "@types/tinycolor2": "^1.4.0", "tinycolor2": "^1.0.0" } }, "sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw=="], + "tinypool": ["tinypool@0.8.4", "", {}, "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ=="], "tinyspy": ["tinyspy@2.2.1", "", {}, "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A=="], @@ -518,6 +525,8 @@ "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + "vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": "bin/esbuild" }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], diff --git a/package.json b/package.json index dfdefcf..88855cc 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,16 @@ { - "name": "create-better-t", + "name": "create-better-t-stack", "version": "1.0.0", "description": "CLI tool to scaffold Better-T Stack projects", "type": "module", "bin": { - "create-better-t": "./dist/index.js" + "create-better-t-stack": "./dist/index.js" }, "scripts": { "build": "tsup", "dev": "tsup --watch", "typecheck": "tsc --noEmit", + "check": "biome check --write .", "test": "vitest run", "prepublishOnly": "npm run build" }, @@ -18,11 +19,12 @@ "templates" ], "dependencies": { - "@drizzle-team/brocli": "^0.11.0", "@inquirer/prompts": "^7.3.1", "chalk": "^5.3.0", + "commander": "^13.1.0", "execa": "^8.0.1", "fs-extra": "^11.2.0", + "gradient-string": "^3.0.0", "ora": "^7.0.1" }, "devDependencies": { diff --git a/src/consts.ts b/src/consts.ts new file mode 100644 index 0000000..029d03d --- /dev/null +++ b/src/consts.ts @@ -0,0 +1,21 @@ +export const TITLE_TEXT = ` + ╔════════════════════════════════════════════════════════════╗ + ║ ║ + ║ ██████╗ ███████╗████████╗████████╗███████╗██████╗ ║ + ║ ██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗ ║ + ║ ██████╔╝█████╗ ██║ ██║ █████╗ ██████╔╝ ║ + ║ ██╔══██╗██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗ ║ + ║ ██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║ ║ + ║ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ║ + ║ ║ + ║ ████████╗ ███████╗████████╗ █████╗ ██████╗██╗ ██╗ ║ + ║ ╚══██╔══╝ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝ ║ + ║ ██║ ███████╗ ██║ ███████║██║ █████╔╝ ║ + ║ ██║ ╚════██║ ██║ ██╔══██║██║ ██╔═██╗ ║ + ║ ██║ ███████║ ██║ ██║ ██║╚██████╗██║ ██╗ ║ + ║ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ║ + ║ ║ + ║ The Modern Full-Stack Framework ║ + ║ ║ + ╚════════════════════════════════════════════════════════════╝ + `; diff --git a/src/index.ts b/src/index.ts index aa41d83..4c87e0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,66 +1,81 @@ -#!/usr/bin/env node - -import { boolean, command, run, string } from "@drizzle-team/brocli"; -import { confirm, input, select } from "@inquirer/prompts"; +import { checkbox, confirm, input, select } from "@inquirer/prompts"; import chalk from "chalk"; -import { createProject } from "./create-project"; +import { Command } from "commander"; +import { createProject } from "./create-project.js"; +import { renderTitle } from "./render-title.js"; +import type { ProjectOptions } from "./types.js"; -const createCommand = command({ - name: "init", - desc: "Create a new Better-T Stack project", - options: { - projectDir: string() - .desc("Project directory name") - .default("my-better-t-app"), - git: boolean().desc("Initialize git repository").default(true), - }, - handler: async (opts) => { - console.log(chalk.bold("\n🚀 Creating a new Better-T Stack project...\n")); +const program = new Command(); - const projectName = - opts.projectDir || - (await input({ - message: "Project name:", - default: "my-better-t-app", - })); +async function main() { + renderTitle(); - const database = await select({ - message: "Select database:", - choices: [ - { value: "libsql", label: "libSQL (recommended)" }, - { value: "postgres", label: "PostgreSQL" }, - ], - }); + console.log(chalk.bold("\n🚀 Creating a new Better-T Stack project...\n")); - const auth = await confirm({ - message: "Add authentication with Better-Auth?", - default: true, - }); + const projectName = await input({ + message: "Project name:", + default: "my-better-t-app", + }); - const features = await select({ - message: "Select additional features:", - choices: [ - { value: "docker", label: "Docker setup" }, - { value: "github-actions", label: "GitHub Actions" }, - { value: "SEO", label: "Basic SEO setup" }, - ], - multiselect: true, - }); + const database = await select({ + message: chalk.cyan("Select database:"), + choices: [ + { + value: "libsql", + name: "libSQL", + description: chalk.dim( + "(Recommended) - Turso's embedded SQLite database", + ), + }, + { + value: "postgres", + name: "PostgreSQL", + description: chalk.dim("Traditional relational database"), + }, + ], + }); - const projectOptions = { - projectName, - git: opts.git, - database, - auth, - features, - }; + const auth = await confirm({ + message: "Add authentication with Better-Auth?", + default: true, + }); - await createProject(projectOptions); - }, -}); + const features = await checkbox({ + message: chalk.cyan("Select additional features:"), + choices: [ + { + value: "docker", + name: "Docker setup", + description: chalk.dim("Containerize your application"), + }, + { + value: "github-actions", + name: "GitHub Actions", + description: chalk.dim("CI/CD workflows"), + }, + { + value: "SEO", + name: "Basic SEO setup", + description: chalk.dim("Search engine optimization configuration"), + }, + ], + }); -run([createCommand], { - name: "create-better-t", - description: "Create a new Better-T Stack project", - version: "1.0.0", -}); + const projectOptions = { + projectName, + git: true, + database, + auth, + features, + }; + + await createProject(projectOptions as ProjectOptions); +} + +program + .name("create-better-t-stack") + .description("Create a new Better-T Stack project") + .version("1.0.0") + .action(main); + +program.parse(); diff --git a/src/render-title.ts b/src/render-title.ts new file mode 100644 index 0000000..4156875 --- /dev/null +++ b/src/render-title.ts @@ -0,0 +1,17 @@ +import gradient from "gradient-string"; +import { TITLE_TEXT } from "./consts"; + +const betterTTheme = { + primary: "#4F46E5", + secondary: "#06B6D4", + accent: "#3B82F6", + highlight: "#8B5CF6", + success: "#10B981", + warning: "#F59E0B", +}; + +export const renderTitle = () => { + const betterTGradient = gradient(Object.values(betterTTheme)); + + console.log(betterTGradient.multiline(TITLE_TEXT)); +}; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..764975d --- /dev/null +++ b/src/types.ts @@ -0,0 +1,8 @@ +export interface ProjectOptions { + projectName: string; + typescript: boolean; + git: boolean; + database: "libsql" | "postgres"; + auth: boolean; + features: string[]; +} diff --git a/tsconfig.json b/tsconfig.json index bda8773..a03e851 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,14 @@ { - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "skipLibCheck": true, - "outDir": "dist" - }, - "include": ["src"] + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "outDir": "dist", + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/tsup.config.ts b/tsup.config.ts index da6de00..6aafb83 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -1,11 +1,14 @@ import { defineConfig } from "tsup"; export default defineConfig({ - entry: ["src/index.ts"], - format: ["esm"], - clean: true, - dts: true, - shims: true, - splitting: false, - outDir: "dist", + entry: ["src/index.ts"], + format: ["esm"], + clean: true, + dts: true, + shims: true, + splitting: false, + outDir: "dist", + banner: { + js: "#!/usr/bin/env node", + }, });