1- import path from "node:path" ;
2- import {
3- cancel ,
4- confirm ,
5- group ,
6- intro ,
7- log ,
8- multiselect ,
9- outro ,
10- select ,
11- spinner ,
12- text ,
13- } from "@clack/prompts" ;
1+ import { cancel , intro , log , outro , spinner } from "@clack/prompts" ;
142import { Command } from "commander" ;
15- import fs from "fs-extra" ;
163import pc from "picocolors" ;
17- import { DEFAULT_CONFIG } from "./consts " ;
4+ import { DEFAULT_CONFIG } from "./constants " ;
185import { createProject } from "./helpers/create-project" ;
19- import type {
20- PackageManager ,
21- ProjectConfig ,
22- ProjectDatabase ,
23- ProjectFeature ,
24- ProjectORM ,
25- } from "./types" ;
6+ import { gatherConfig } from "./prompts/config-prompts" ;
7+ import type { PackageManager , ProjectConfig , ProjectFeature } from "./types" ;
8+ import { displayConfig } from "./utils/display-config" ;
269import { generateReproducibleCommand } from "./utils/generate-reproducible-command" ;
27- import { getUserPkgManager } from "./utils/get-package-manager" ;
2810import { getVersion } from "./utils/get-version" ;
2911import { renderTitle } from "./utils/render-title" ;
3012
@@ -35,215 +17,6 @@ process.on("SIGINT", () => {
3517
3618const program = new Command ( ) ;
3719
38- async function gatherConfig (
39- flags : Partial < ProjectConfig > ,
40- ) : Promise < ProjectConfig > {
41- const result = await group (
42- {
43- projectName : async ( ) => {
44- if ( flags . projectName ) return flags . projectName ;
45- let isValid = false ;
46- let projectName : string | symbol = "" ;
47- let defaultName = DEFAULT_CONFIG . projectName ;
48- let counter = 1 ;
49-
50- while ( fs . pathExistsSync ( path . resolve ( process . cwd ( ) , defaultName ) ) ) {
51- defaultName = `${ DEFAULT_CONFIG . projectName } -${ counter } ` ;
52- counter ++ ;
53- }
54-
55- while ( ! isValid ) {
56- const response = await text ( {
57- message : "What is your project named? (directory name or path)" ,
58- placeholder : defaultName ,
59- initialValue : flags . projectName ,
60- defaultValue : defaultName ,
61- validate : ( value ) => {
62- const nameToUse = value . trim ( ) || defaultName ;
63- const projectDir = path . resolve ( process . cwd ( ) , nameToUse ) ;
64-
65- if ( fs . pathExistsSync ( projectDir ) ) {
66- const dirContents = fs . readdirSync ( projectDir ) ;
67- if ( dirContents . length > 0 ) {
68- return `Directory "${ nameToUse } " already exists and is not empty. Please choose a different name.` ;
69- }
70- }
71-
72- isValid = true ;
73- return undefined ;
74- } ,
75- } ) ;
76-
77- if ( typeof response === "symbol" ) {
78- cancel ( pc . red ( "Operation cancelled." ) ) ;
79- process . exit ( 0 ) ;
80- }
81-
82- projectName = response || defaultName ;
83- }
84-
85- return projectName as string ;
86- } ,
87- database : ( ) =>
88- flags . database !== undefined
89- ? Promise . resolve ( flags . database )
90- : select < ProjectDatabase > ( {
91- message : "Which database would you like to use?" ,
92- options : [
93- {
94- value : "sqlite" ,
95- label : "SQLite" ,
96- hint : "by Turso (recommended)" ,
97- } ,
98- {
99- value : "postgres" ,
100- label : "PostgreSQL" ,
101- hint : "Traditional relational database" ,
102- } ,
103- ] ,
104- } ) ,
105- orm : ( ) =>
106- flags . orm !== undefined
107- ? Promise . resolve ( flags . orm )
108- : select < ProjectORM > ( {
109- message : "Which ORM would you like to use?" ,
110- options : [
111- {
112- value : "drizzle" ,
113- label : "Drizzle" ,
114- hint : "Type-safe, lightweight ORM (recommended)" ,
115- } ,
116- // {
117- // value: "prisma",
118- // label: "Prisma (coming soon)",
119- // hint: "Feature-rich ORM with great DX",
120- // },
121- ] ,
122- initialValue : "drizzle" ,
123- } ) ,
124- auth : ( ) =>
125- flags . auth !== undefined
126- ? Promise . resolve ( flags . auth )
127- : confirm ( {
128- message : "Would you like to add authentication with Better-Auth?" ,
129- initialValue : DEFAULT_CONFIG . auth ,
130- } ) ,
131- features : ( ) =>
132- flags . features !== undefined
133- ? Promise . resolve ( flags . features )
134- : multiselect < ProjectFeature > ( {
135- message : "Which features would you like to add?" ,
136- options : [
137- {
138- value : "docker" ,
139- label : "Docker setup" ,
140- hint : "Containerize your application" ,
141- } ,
142- {
143- value : "github-actions" ,
144- label : "GitHub Actions" ,
145- hint : "CI/CD workflows" ,
146- } ,
147- {
148- value : "SEO" ,
149- label : "Basic SEO setup" ,
150- hint : "Search engine optimization configuration" ,
151- } ,
152- ] ,
153- required : false ,
154- } ) ,
155- git : ( ) =>
156- flags . git !== undefined
157- ? Promise . resolve ( flags . git )
158- : confirm ( {
159- message : "Initialize a new git repository?" ,
160- initialValue : DEFAULT_CONFIG . git ,
161- } ) ,
162- packageManager : async ( ) => {
163- if ( flags . packageManager !== undefined ) {
164- return flags . packageManager ;
165- }
166- const detectedPackageManager = getUserPkgManager ( ) ;
167-
168- const useDetected = await confirm ( {
169- message : `Use ${ detectedPackageManager } as your package manager?` ,
170- } ) ;
171-
172- if ( useDetected ) return detectedPackageManager ;
173-
174- return select < PackageManager > ( {
175- message : "Which package manager would you like to use?" ,
176- options : [
177- { value : "npm" , label : "npm" , hint : "Node Package Manager" } ,
178- {
179- value : "pnpm" ,
180- label : "pnpm" ,
181- hint : "Fast, disk space efficient package manager" ,
182- } ,
183- {
184- value : "yarn" ,
185- label : "yarn" ,
186- hint : "Fast, reliable, and secure dependency management" ,
187- } ,
188- {
189- value : "bun" ,
190- label : "bun" ,
191- hint : "All-in-one JavaScript runtime & toolkit (recommended)" ,
192- } ,
193- ] ,
194- initialValue : "bun" ,
195- } ) ;
196- } ,
197- } ,
198- {
199- onCancel : ( ) => {
200- cancel ( pc . red ( "Operation cancelled." ) ) ;
201- process . exit ( 0 ) ;
202- } ,
203- } ,
204- ) ;
205-
206- return {
207- projectName : result . projectName ?? DEFAULT_CONFIG . projectName ,
208- database : result . database ?? DEFAULT_CONFIG . database ,
209- orm : result . orm ?? DEFAULT_CONFIG . orm ,
210- auth : result . auth ?? DEFAULT_CONFIG . auth ,
211- features : result . features ?? DEFAULT_CONFIG . features ,
212- git : result . git ?? DEFAULT_CONFIG . git ,
213- packageManager : result . packageManager ?? DEFAULT_CONFIG . packageManager ,
214- } ;
215- }
216-
217- function displayConfig ( config : Partial < ProjectConfig > ) {
218- const configDisplay = [ ] ;
219-
220- if ( config . projectName ) {
221- configDisplay . push ( `${ pc . blue ( "Project Name:" ) } ${ config . projectName } ` ) ;
222- }
223- if ( config . database ) {
224- configDisplay . push ( `${ pc . blue ( "Database:" ) } ${ config . database } ` ) ;
225- }
226- if ( config . orm ) {
227- configDisplay . push ( `${ pc . blue ( "ORM:" ) } ${ config . orm } ` ) ;
228- }
229- if ( config . auth !== undefined ) {
230- configDisplay . push ( `${ pc . blue ( "Authentication:" ) } ${ config . auth } ` ) ;
231- }
232- if ( config . features ?. length ) {
233- configDisplay . push ( `${ pc . blue ( "Features:" ) } ${ config . features . join ( ", " ) } ` ) ;
234- }
235- if ( config . git !== undefined ) {
236- configDisplay . push ( `${ pc . blue ( "Git Init:" ) } ${ config . git } ` ) ;
237- }
238- if ( config . packageManager ) {
239- configDisplay . push (
240- `${ pc . blue ( "Package Manager:" ) } ${ config . packageManager } ` ,
241- ) ;
242- }
243-
244- return configDisplay . join ( "\n" ) ;
245- }
246-
24720async function main ( ) {
24821 const s = spinner ( ) ;
24922 try {
@@ -256,6 +29,7 @@ async function main() {
25629 . version ( getVersion ( ) )
25730 . argument ( "[project-directory]" , "Project name/directory" )
25831 . option ( "-y, --yes" , "Use default configuration" )
32+ . option ( "--no-database" , "Skip database setup" )
25933 . option ( "--sqlite" , "Use SQLite database" )
26034 . option ( "--postgres" , "Use PostgreSQL database" )
26135 . option ( "--auth" , "Include authentication" )
@@ -277,38 +51,28 @@ async function main() {
27751 const projectDirectory = program . args [ 0 ] ;
27852
27953 const flagConfig : Partial < ProjectConfig > = {
280- projectName : projectDirectory || undefined ,
281- database : options . sqlite
282- ? "sqlite"
283- : options . postgres
284- ? "postgres"
285- : undefined ,
286- orm : options . drizzle ? "drizzle" : options . prisma ? "prisma" : undefined ,
287- auth : "auth" in options ? options . auth : undefined ,
288- packageManager : options . npm
289- ? "npm"
290- : options . pnpm
291- ? "pnpm"
292- : options . yarn
293- ? "yarn"
294- : options . bun
295- ? "bun"
296- : undefined ,
297- git : "git" in options ? options . git : undefined ,
298- features :
299- options . docker || options . githubActions || options . seo
300- ? ( [
301- ...( options . docker ? [ "docker" ] : [ ] ) ,
302- ...( options . githubActions ? [ "github-actions" ] : [ ] ) ,
303- ...( options . seo ? [ "SEO" ] : [ ] ) ,
304- ] as ProjectFeature [ ] )
305- : undefined ,
54+ ...( projectDirectory && { projectName : projectDirectory } ) ,
55+ ...( options . database === false && { database : "none" } ) ,
56+ ...( options . sqlite && { database : "sqlite" } ) ,
57+ ...( options . postgres && { database : "postgres" } ) ,
58+ ...( options . drizzle && { orm : "drizzle" } ) ,
59+ ...( options . prisma && { orm : "prisma" } ) ,
60+ ...( "auth" in options && { auth : options . auth } ) ,
61+ ...( options . npm && { packageManager : "npm" } ) ,
62+ ...( options . pnpm && { packageManager : "pnpm" } ) ,
63+ ...( options . yarn && { packageManager : "yarn" } ) ,
64+ ...( options . bun && { packageManager : "bun" } ) ,
65+ ...( "git" in options && { git : options . git } ) ,
66+ ...( ( options . docker || options . githubActions || options . seo ) && {
67+ features : [
68+ ...( options . docker ? [ "docker" ] : [ ] ) ,
69+ ...( options . githubActions ? [ "github-actions" ] : [ ] ) ,
70+ ...( options . seo ? [ "SEO" ] : [ ] ) ,
71+ ] as ProjectFeature [ ] ,
72+ } ) ,
30673 } ;
30774
308- if (
309- ! options . yes &&
310- Object . values ( flagConfig ) . some ( ( v ) => v !== undefined )
311- ) {
75+ if ( ! options . yes && Object . keys ( flagConfig ) . length > 0 ) {
31276 log . info ( pc . yellow ( "Using these pre-selected options:" ) ) ;
31377 log . message ( displayConfig ( flagConfig ) ) ;
31478 log . message ( "" ) ;
@@ -317,23 +81,26 @@ async function main() {
31781 const config = options . yes
31882 ? {
31983 ...DEFAULT_CONFIG ,
320- yes : true ,
32184 projectName : projectDirectory ?? DEFAULT_CONFIG . projectName ,
322- database : options . database ?? DEFAULT_CONFIG . database ,
323- orm : options . drizzle
324- ? "drizzle"
325- : options . prisma
326- ? "prisma"
327- : DEFAULT_CONFIG . orm , // Add this line
85+ database :
86+ options . database === false
87+ ? "none"
88+ : ( options . database ?? DEFAULT_CONFIG . database ) ,
89+ orm :
90+ options . database === false
91+ ? "none"
92+ : options . drizzle
93+ ? "drizzle"
94+ : options . prisma
95+ ? "prisma"
96+ : DEFAULT_CONFIG . orm ,
32897 auth : options . auth ?? DEFAULT_CONFIG . auth ,
32998 git : options . git ?? DEFAULT_CONFIG . git ,
33099 packageManager :
331- options . packageManager ?? DEFAULT_CONFIG . packageManager ,
332- features : [
333- ...( options . docker ? [ "docker" ] : [ ] ) ,
334- ...( options . githubActions ? [ "github-actions" ] : [ ] ) ,
335- ...( options . seo ? [ "SEO" ] : [ ] ) ,
336- ] as ProjectFeature [ ] ,
100+ flagConfig . packageManager ?? DEFAULT_CONFIG . packageManager ,
101+ features : flagConfig . features ?. length
102+ ? flagConfig . features
103+ : DEFAULT_CONFIG . features ,
337104 }
338105 : await gatherConfig ( flagConfig ) ;
339106
0 commit comments