add express, automated mongodb atlas setup, fix stack architech

This commit is contained in:
Aman Varshney
2025-04-07 21:32:22 +05:30
parent c6c73fce76
commit 2cf01d155b
38 changed files with 902 additions and 393 deletions

View File

@@ -16,6 +16,11 @@ export async function getBackendFrameworkChoice(
label: "Hono",
hint: "Lightweight, ultrafast web framework",
},
{
value: "express",
label: "Express",
hint: "Fast, unopinionated, minimalist web framework for Node.js",
},
{
value: "elysia",
label: "Elysia",

View File

@@ -1,9 +1,10 @@
import { cancel, group } from "@clack/prompts";
import { cancel, group, log } from "@clack/prompts";
import pc from "picocolors";
import type {
ProjectAddons,
ProjectBackend,
ProjectConfig,
ProjectDBSetup,
ProjectDatabase,
ProjectExamples,
ProjectFrontend,
@@ -15,16 +16,15 @@ import { getAddonsChoice } from "./addons";
import { getAuthChoice } from "./auth";
import { getBackendFrameworkChoice } from "./backend-framework";
import { getDatabaseChoice } from "./database";
import { getDBSetupChoice } from "./db-setup";
import { getExamplesChoice } from "./examples";
import { getFrontendChoice } from "./frontend-option";
import { getGitChoice } from "./git";
import { getNoInstallChoice } from "./install";
import { getORMChoice } from "./orm";
import { getPackageManagerChoice } from "./package-manager";
import { getPrismaSetupChoice } from "./prisma-postgres";
import { getProjectName } from "./project-name";
import { getRuntimeChoice } from "./runtime";
import { getTursoSetupChoice } from "./turso";
type PromptGroupResults = {
projectName: string;
@@ -36,8 +36,7 @@ type PromptGroupResults = {
git: boolean;
packageManager: ProjectPackageManager;
noInstall: boolean;
turso: boolean;
prismaPostgres: boolean;
dbSetup: ProjectDBSetup;
backend: ProjectBackend;
runtime: ProjectRuntime;
frontend: ProjectFrontend[];
@@ -46,6 +45,32 @@ type PromptGroupResults = {
export async function gatherConfig(
flags: Partial<ProjectConfig>,
): Promise<ProjectConfig> {
// Handle specific dbSetup scenarios to adjust database and ORM before prompts
if (flags.dbSetup) {
if (flags.dbSetup === "turso") {
// Force database to be sqlite when turso is selected
flags.database = "sqlite";
// If orm is explicitly set to prisma, warn and switch to drizzle
if (flags.orm === "prisma") {
log.warn(
pc.yellow(
"Turso is not compatible with Prisma - switching to Drizzle",
),
);
flags.orm = "drizzle";
}
} else if (flags.dbSetup === "prisma-postgres") {
// Force database and orm for prisma-postgres
flags.database = "postgres";
flags.orm = "prisma";
} else if (flags.dbSetup === "mongodb-atlas") {
// Force database for mongodb-atlas
flags.database = "mongodb";
flags.orm = "prisma"; // MongoDB only works with Prisma
}
}
const result = await group<PromptGroupResults>(
{
projectName: async () => {
@@ -56,21 +81,15 @@ export async function gatherConfig(
runtime: () => getRuntimeChoice(flags.runtime),
database: () => getDatabaseChoice(flags.database),
orm: ({ results }) =>
getORMChoice(flags.orm, results.database !== "none"),
getORMChoice(flags.orm, results.database !== "none", results.database),
auth: ({ results }) =>
getAuthChoice(
flags.auth,
results.database !== "none",
results.frontend,
),
turso: ({ results }) =>
results.database === "sqlite" && results.orm !== "prisma"
? getTursoSetupChoice(flags.turso)
: Promise.resolve(false),
prismaPostgres: ({ results }) =>
results.database === "postgres" && results.orm === "prisma"
? getPrismaSetupChoice(flags.prismaPostgres)
: Promise.resolve(false),
dbSetup: ({ results }) =>
getDBSetupChoice(results.database ?? "none", flags.dbSetup),
addons: ({ results }) => getAddonsChoice(flags.addons, results.frontend),
examples: ({ results }) =>
getExamplesChoice(
@@ -102,8 +121,7 @@ export async function gatherConfig(
git: result.git,
packageManager: result.packageManager,
noInstall: result.noInstall,
turso: result.turso,
prismaPostgres: result.prismaPostgres,
dbSetup: result.dbSetup,
backend: result.backend,
runtime: result.runtime,
};

View File

@@ -26,6 +26,11 @@ export async function getDatabaseChoice(
label: "PostgreSQL",
hint: "Traditional relational database",
},
{
value: "mongodb",
label: "MongoDB",
hint: "NoSQL document-oriented database",
},
],
initialValue: DEFAULT_CONFIG.database,
});

View File

@@ -0,0 +1,57 @@
import { cancel, isCancel, select } from "@clack/prompts";
import pc from "picocolors";
import type { ProjectDBSetup } from "../types";
export async function getDBSetupChoice(
databaseType: string,
dbSetup: ProjectDBSetup | undefined,
): Promise<ProjectDBSetup> {
if (dbSetup !== undefined) return dbSetup as ProjectDBSetup;
let options: Array<{ value: ProjectDBSetup; label: string; hint: string }> =
[];
if (databaseType === "sqlite") {
options = [
{
value: "turso" as const,
label: "Turso",
hint: "Cloud SQLite with libSQL",
},
{ value: "none" as const, label: "None", hint: "Manual setup" },
];
} else if (databaseType === "postgres") {
options = [
{
value: "prisma-postgres" as const,
label: "Prisma Postgres",
hint: "Managed by Prisma",
},
{ value: "none" as const, label: "None", hint: "Manual setup" },
];
} else if (databaseType === "mongodb") {
options = [
{
value: "mongodb-atlas" as const,
label: "MongoDB Atlas",
hint: "Cloud MongoDB service",
},
{ value: "none" as const, label: "None", hint: "Manual setup" },
];
} else {
return "none";
}
const response = await select<ProjectDBSetup>({
message: `Select ${databaseType} setup option`,
options,
initialValue: "none",
});
if (isCancel(response)) {
cancel(pc.red("Operation cancelled"));
process.exit(0);
}
return response;
}

View File

@@ -42,7 +42,7 @@ export async function getExamplesChoice(
});
}
if (backend === "hono") {
if (backend === "hono" || backend === "express") {
response = await multiselect<ProjectExamples>({
message: "Include examples",
options: [

View File

@@ -1,15 +1,21 @@
import { cancel, isCancel, select } from "@clack/prompts";
import { cancel, isCancel, log, select } from "@clack/prompts";
import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants";
import type { ProjectOrm } from "../types";
import type { ProjectDatabase, ProjectOrm } from "../types";
export async function getORMChoice(
orm: ProjectOrm | undefined,
hasDatabase: boolean,
database?: ProjectDatabase,
): Promise<ProjectOrm> {
if (!hasDatabase) return "none";
if (orm !== undefined) return orm;
if (database === "mongodb") {
log.info("Only Prisma is supported with MongoDB.");
return "prisma";
}
const response = await select<ProjectOrm>({
message: "Select ORM",
options: [

View File

@@ -1,21 +0,0 @@
import { cancel, confirm, isCancel } from "@clack/prompts";
import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants";
export async function getPrismaSetupChoice(
prismaSetup?: boolean,
): Promise<boolean> {
if (prismaSetup !== undefined) return prismaSetup;
const response = await confirm({
message: "Set up Prisma Postgres database?",
initialValue: DEFAULT_CONFIG.prismaPostgres,
});
if (isCancel(response)) {
cancel(pc.red("Operation cancelled"));
process.exit(0);
}
return response;
}

View File

@@ -1,19 +0,0 @@
import { cancel, confirm, isCancel } from "@clack/prompts";
import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants";
export async function getTursoSetupChoice(turso?: boolean): Promise<boolean> {
if (turso !== undefined) return turso;
const response = await confirm({
message: "Set up Turso database?",
initialValue: DEFAULT_CONFIG.turso,
});
if (isCancel(response)) {
cancel(pc.red("Operation cancelled"));
process.exit(0);
}
return response;
}