@@ -11,17 +11,20 @@ import {
1111 runIgnite ,
1212 showHelp
1313} from '../utilities' ;
14- import { DEFAULT_APP_NAME , defaultOptions } from '../constants' ;
14+ import {
15+ bunInstallationError ,
16+ DEFAULT_APP_NAME ,
17+ defaultOptions ,
18+ nativeWindUIOptions ,
19+ navigationValidationError ,
20+ projectNameValidationError
21+ } from '../constants' ;
1522import { CliResults , availablePackages } from '../types' ;
1623import clearStylingPackages from '../utilities/clearStylingPackages' ;
1724import { validateProjectName } from '../utilities/validateProjectName' ;
1825import { cancel , intro , isCancel , text } from '@clack/prompts' ;
1926import clearNavigationPackages from '../utilities/clearNavigationPackages' ;
2027
21- const navigationValidationError = `You must pass in either --react-navigation or --expo-router if you want to use the --tabs or --drawer+tabs options` ;
22- const projectNameValidationError = `A project with the name` ;
23- const bunInstallationError = 'User cancelled to install recommended version of Bun.' ;
24-
2528const command : GluegunCommand = {
2629 name : 'create-expo-stack' ,
2730 description : 'Create a new Expo project' ,
@@ -36,7 +39,7 @@ const command: GluegunCommand = {
3639 const printSomethingWentWrong = ( ) => {
3740 info ( `\nOops, something went wrong while creating your project 😢` ) ;
3841 info (
39- `\nIf this was unexpected, please open an issue: https://github.com/danstepanov /create-expo-stack#reporting-bugs--feedback`
42+ `\nIf this was unexpected, please open an issue: https://github.com/roninoss /create-expo-stack#reporting-bugs--feedback`
4043 ) ;
4144 info ( '' ) ;
4245 } ;
@@ -69,7 +72,9 @@ const command: GluegunCommand = {
6972 ! options . reactnavigation &&
7073 ! options . expoRouter &&
7174 ! options [ 'expo-router' ] &&
72- ! options . exporouter
75+ ! options . exporouter &&
76+ // nativewindui applies the expo router option by default
77+ ! options . nativewindui
7378 ) {
7479 // throw an error without a stack trace
7580 throw navigationValidationError ;
@@ -107,6 +112,10 @@ const command: GluegunCommand = {
107112 cliResults . flags . overwrite = true ;
108113 }
109114
115+ if ( options . eas ) {
116+ cliResults . flags . eas = true ;
117+ }
118+
110119 await validateProjectName (
111120 exists ,
112121 removeAsync ,
@@ -115,6 +124,10 @@ const command: GluegunCommand = {
115124 cliResults . flags . overwrite
116125 ) ;
117126 } catch ( err : string | any ) {
127+ if ( process . env . NODE_ENV === 'test' || process . env . NODE_ENV === 'development' ) {
128+ error ( `error: ${ err } ` ) ;
129+ }
130+
118131 if ( err === '' ) {
119132 // user cancelled/exited the interactive CLI
120133 return void success ( `\nCancelled... 👋 \n` ) ;
@@ -127,8 +140,11 @@ const command: GluegunCommand = {
127140 return void success ( `\nCancelled... 👋 \n` ) ;
128141 }
129142
130- // Delete all files with projectName
131- await removeAsync ( cliResults . projectName ) ;
143+ // we keep this around so we can check what went wrong
144+ if ( process . env . NODE_ENV !== 'test' ) {
145+ // Delete all files with projectName
146+ await removeAsync ( cliResults . projectName ) ;
147+ }
132148
133149 printSomethingWentWrong ( ) ;
134150 throw err ;
@@ -196,38 +212,30 @@ const command: GluegunCommand = {
196212 } else if ( options . nativewindui ) {
197213 cliResults = clearStylingPackages ( cliResults ) ;
198214 cliResults = clearNavigationPackages ( cliResults ) ;
215+
216+ const parsedComponents =
217+ options ?. selectedComponents
218+ ?. split ( ',' )
219+ ?. map ( ( c : string ) => c . trim ( ) )
220+ ?. filter ( ( item ) => nativeWindUIOptions . includes ( item ) ) ?? [ ] ;
221+
222+ const selectedComponents = parsedComponents . length
223+ ? Array . from ( new Set ( [ ...parsedComponents , 'text' ] ) )
224+ : nativeWindUIOptions ;
225+
199226 cliResults . packages . push ( {
200227 name : 'nativewindui' ,
201228 type : 'styling' ,
202229 options : {
203- selectedComponents : options . blank
204- ? [ ]
205- : [
206- 'action-sheet' ,
207- 'activity-indicator' ,
208- 'activity-view' ,
209- 'alert' ,
210- 'avatar' ,
211- 'bottom-sheet' ,
212- 'context-menu' ,
213- 'date-picker' ,
214- 'dropdown-menu' ,
215- 'picker' ,
216- 'progress-indicator' ,
217- 'ratings-indicator' ,
218- 'segmented-control' ,
219- 'selectable-text' ,
220- 'slider' ,
221- 'text' ,
222- 'toggle'
223- ]
230+ selectedComponents : options . blank ? [ 'text' ] : selectedComponents
224231 }
225232 } ) ;
233+
226234 cliResults . packages . push ( {
227235 name : 'expo-router' ,
228236 type : 'navigation' ,
229237 options : {
230- type : ' drawer + tabs'
238+ type : options . tabs ? 'tabs' : options [ ' drawer+tabs' ] ? 'drawer + tabs' : 'stack '
231239 }
232240 } ) ;
233241 } else if ( options . tamagui ) {
@@ -288,6 +296,15 @@ const command: GluegunCommand = {
288296 } ) ;
289297 }
290298
299+ // State Management packages
300+ if ( options . zustand ) {
301+ // Add zustand package
302+ cliResults . packages . push ( {
303+ name : 'zustand' ,
304+ type : 'state-management'
305+ } ) ;
306+ }
307+
291308 // Internalization packages
292309 if ( options . i18next ) {
293310 cliResults . packages . push ( {
@@ -296,6 +313,11 @@ const command: GluegunCommand = {
296313 } ) ;
297314 }
298315
316+ // Analytics packages
317+ if ( options . vexoAnalytics || options [ 'vexo-analytics' ] || options . vexoanalytics ) {
318+ cliResults . packages . push ( { name : 'vexo-analytics' , type : 'analytics' } ) ;
319+ }
320+
299321 // By this point, all cliResults should be set
300322 info ( '' ) ;
301323 highlight ( 'Your project configuration:' ) ;
@@ -306,12 +328,47 @@ const command: GluegunCommand = {
306328
307329 // Function that outputs a string given the CLI results and the packageManager. The outputted string should be a command that can be run to recreate the project
308330 const generateRerunScript = ( cliResults : CliResults ) => {
309- let script = `npx create-expo-stack ${ cliResults . projectName } ` ;
331+ let script = `npx create-expo-stack@latest ${ cliResults . projectName } ` ;
332+
333+ const isNativeWindUISelected = cliResults . packages . some ( ( p ) => p . name === 'nativewindui' ) ;
310334
311- if ( cliResults . packages . length > 0 && cliResults . packages [ 0 ] . name === 'nativewindui' ) {
335+ if ( isNativeWindUISelected ) {
312336 script += '--nativewindui ' ;
313- if ( cliResults . packages [ 0 ] . options . selectedComponents . length === 0 ) {
337+
338+ const nativeWindUIComponents =
339+ cliResults . packages . find ( ( p ) => p . name === 'nativewindui' ) ?. options . selectedComponents ?? [ ] ;
340+
341+ // we do this to account for older stored config e.g that has selectable text in it
342+ const onlyValidComponents = nativeWindUIComponents . filter ( ( c ) => nativeWindUIOptions . includes ( c ) ) ;
343+
344+ if ( onlyValidComponents . length === 0 ) {
314345 script += '--blank ' ;
346+ } else if ( onlyValidComponents . length !== nativeWindUIOptions . length ) {
347+ script += `--selected-components=${ onlyValidComponents . join ( ',' ) } ` ;
348+ }
349+
350+ // this should always be expo router for nwui
351+ const chosenNavigationOption = cliResults . packages . find ( ( p ) => p . type === 'navigation' ) ;
352+
353+ const hasNavigationPackage = chosenNavigationOption !== undefined ;
354+
355+ const navigationType = chosenNavigationOption . options . type ;
356+
357+ if ( hasNavigationPackage ) {
358+ // NOTE we don't need to add expo-router since its currently getting automatically added with nativewindui
359+ // NOTE stack is default so doesn't need to applied.
360+ if ( navigationType === 'tabs' ) {
361+ script += '--tabs ' ;
362+ } else if ( navigationType === 'drawer + tabs' ) {
363+ script += '--drawer+tabs ' ;
364+ }
365+ }
366+
367+ const stateManagementPackage = cliResults . packages . find ( ( p ) => p . type === 'state-management' ) ;
368+
369+ if ( stateManagementPackage ) {
370+ // currently only redux is supported
371+ script += `--${ stateManagementPackage . name } ` ;
315372 }
316373 } else {
317374 // Add the packages
@@ -347,6 +404,10 @@ const command: GluegunCommand = {
347404 script += `--${ cliResults . flags . packageManager } ` ;
348405 }
349406
407+ if ( cliResults . flags . eas ) {
408+ script += ` --eas` ;
409+ }
410+
350411 return script ;
351412 } ;
352413
@@ -361,6 +422,10 @@ const command: GluegunCommand = {
361422 // if there is no styling package, add the stylesheet package
362423 const stylingPackage = packages . find ( ( p ) => p . type === 'styling' ) ;
363424 const internalizationPackage = packages . find ( ( p ) => p . type === 'internationalization' ) ;
425+ const analyticsPackage = packages . find ( ( p ) => p . type === 'analytics' ) ;
426+
427+ //add the state management package if it is selected
428+ const stateManagementPackage = packages . find ( ( p ) => p . type === 'state-management' ) || undefined ;
364429
365430 let files : string [ ] = [ ] ;
366431
@@ -369,40 +434,50 @@ const command: GluegunCommand = {
369434 files ,
370435 navigationPackage ,
371436 stylingPackage ,
437+ analyticsPackage ,
372438 toolbox ,
373439 cliResults ,
374- internalizationPackage
440+ internalizationPackage ,
441+ stateManagementPackage
375442 ) ;
376443
377444 // Once all the files are defined, format and generate them
378445 let formattedFiles : any [ ] = [ ] ;
379446
380447 formattedFiles = generateProjectFiles (
381448 authenticationPackage ,
449+ analyticsPackage ,
382450 cliResults ,
383451 files ,
384452 formattedFiles ,
385453 navigationPackage ,
386454 packageManager ,
387455 stylingPackage ,
388456 toolbox ,
389- internalizationPackage
457+ internalizationPackage ,
458+ stateManagementPackage
390459 ) ;
391460
392461 await printOutput ( cliResults , formattedFiles , toolbox , stylingPackage ) ;
393462 }
394463 } catch ( err ) {
464+ if ( process . env . NODE_ENV === 'test' || process . env . NODE_ENV === 'development' ) {
465+ error ( `error: ${ err } ` ) ;
466+ }
467+
395468 if ( err === '' ) {
396469 // user cancelled/exited the interactive CLI
397470 return void success ( `\nCancelled... 👋 \n` ) ;
398471 }
399472
400473 if ( err . message . includes ( bunInstallationError ) ) {
401- return void success ( `\nUser cancelled to install recommended version of Bun... 👋 \n` ) ;
474+ return void success ( `\nCancelled to install recommended version of Bun. ... 👋 \n` ) ;
402475 }
403476
404- // Delete all files with projectName
405- await removeAsync ( cliResults . projectName ) ;
477+ if ( process . env . NODE_ENV !== 'test' ) {
478+ // Delete all files with projectName
479+ await removeAsync ( cliResults . projectName ) ;
480+ }
406481
407482 printSomethingWentWrong ( ) ;
408483 throw err ;
0 commit comments