@@ -6,6 +6,7 @@ import fs from "fs";
66import path from "path" ;
77import { fileURLToPath } from "url" ;
88import { execSync } from "child_process" ;
9+
910// THIRD-PARTY MODULES
1011import ora from "ora" ;
1112import chalk from "chalk" ;
@@ -15,9 +16,8 @@ import inquirer from "inquirer";
1516// Get the directory name of the current module
1617const __filename = fileURLToPath ( import . meta. url ) ;
1718const __dirname = path . dirname ( __filename ) ;
18- const options = { name : "RN Setup by Sumit Singh Rathore" } ;
1919
20- // Function to check if a command exists
20+ /** Function to check if a command exists */
2121function checkCommand ( command : string ) : boolean {
2222 try {
2323 execSync ( `where ${ command } ` ) ;
@@ -27,25 +27,35 @@ function checkCommand(command: string): boolean {
2727 }
2828}
2929
30- // Function to install Chocolatey
31- async function installChocolatey ( ) {
32- const spinner = ora ( { text : chalk . blue ( "Installing Chocolatey..." ) } ) . start ( ) ;
30+ /** Retry function */
31+ async function retry ( task : ( ) => Promise < void > , retries = 3 ) : Promise < void > {
32+ for ( let attempt = 0 ; attempt < retries ; attempt ++ ) {
33+ try {
34+ await task ( ) ;
35+ return ; // Exit if the task succeeds
36+ } catch ( error ) {
37+ console . error ( error ) ;
38+ if ( attempt === retries - 1 ) throw new Error ( "Max retries reached" ) ;
39+ console . log ( `Retrying... (${ attempt + 1 } /${ retries } )` ) ;
40+ }
41+ }
42+ }
3343
44+ /** Function to install Chocolatey */
45+ async function installChocolatey ( ) : Promise < void > {
46+ const spinner = ora ( { text : chalk . blue ( "Installing Chocolatey..." ) } ) . start ( ) ;
3447 try {
3548 const admin = await isAdmin ( ) ;
36-
3749 // Check if Chocolatey is already installed
3850 if ( checkCommand ( "choco" ) ) {
3951 spinner . succeed ( chalk . green ( "Chocolatey is already installed." ) ) ;
4052 return ;
4153 }
42-
4354 if ( ! admin ) {
4455 spinner . info (
4556 chalk . yellow ( "Running Chocolatey installation as non-admin..." )
4657 ) ;
47- const scriptPath = path . join ( __dirname , "ChocolateyInstallNonAdmin.ps1" ) ; // Adjust this path as necessary
48-
58+ const scriptPath = path . join ( __dirname , "ChocolateyInstallNonAdmin.ps1" ) ;
4959 // Execute the PowerShell script for non-admin installation
5060 execSync ( `powershell.exe -ExecutionPolicy Bypass -File "${ scriptPath } "` , {
5161 stdio : "inherit" ,
@@ -62,7 +72,6 @@ async function installChocolatey() {
6272 ) ;
6373 spinner . succeed ( chalk . green ( "Chocolatey installed successfully." ) ) ;
6474 }
65-
6675 // Add Chocolatey to the current session's PATH
6776 const chocoPath = `${ process . env . ProgramData } \\chocoportable\\bin` ;
6877 process . env . PATH = `${ process . env . PATH } ;${ chocoPath } ` ;
@@ -73,12 +82,11 @@ async function installChocolatey() {
7382 }
7483}
7584
76- // Function to install JDK
77- async function installJDK ( ) {
85+ /** Function to install JDK */
86+ async function installJDK ( ) : Promise < void > {
7887 const spinner = ora ( {
7988 text : chalk . blue ( "Checking for JDK installation..." ) ,
8089 } ) . start ( ) ;
81-
8290 spinner . stop ( ) ;
8391 if ( process . platform === "win32" ) {
8492 if ( ! checkCommand ( "java" ) ) {
@@ -88,7 +96,7 @@ async function installJDK() {
8896 await installChocolatey ( ) ;
8997 }
9098 try {
91- execSync ( "choco install -y microsoft-openjdk17" , { stdio : "inherit" } ) ;
99+ execSync ( "choco install microsoft-openjdk17" , { stdio : "inherit" } ) ;
92100 spinner . succeed ( chalk . green ( "OpenJDK installed successfully." ) ) ;
93101 } catch ( error ) {
94102 spinner . fail ( chalk . red ( "Failed to install OpenJDK." ) ) ;
@@ -125,11 +133,15 @@ async function installJDK() {
125133 }
126134}
127135
128- // Function to install Android Studio
129- async function installAndroidStudio ( ) {
136+ /** Function to install Android Studio */
137+ async function installAndroidStudio ( ) : Promise < void > {
130138 const spinner = ora ( {
131139 text : chalk . blue ( "Checking for Android Studio installation..." ) ,
132140 } ) . start ( ) ;
141+ spinner . stop ( ) ;
142+ if ( ! checkCommand ( "choco" ) ) {
143+ await installChocolatey ( ) ;
144+ }
133145
134146 const androidStudioPath = path . join (
135147 process . env . ProgramFiles || "C:\\Program Files" ,
@@ -139,21 +151,16 @@ async function installAndroidStudio() {
139151 "studio.exe"
140152 ) ;
141153
142- spinner . stop ( ) ;
143-
144154 if ( process . platform === "win32" ) {
145155 if ( ! fs . existsSync ( androidStudioPath ) ) {
146156 spinner . text = chalk . yellow ( "Installing Android Studio..." ) ;
147157 spinner . start ( ) ;
148158 try {
149159 // Path to your PowerShell script
150160 const scriptPath = path . join ( __dirname , "AndroidStudioInstall.ps1" ) ;
151-
152- // Run the PowerShell script
153161 execSync ( `powershell -ExecutionPolicy Bypass -File "${ scriptPath } "` , {
154162 stdio : "inherit" ,
155163 } ) ;
156-
157164 spinner . succeed ( chalk . green ( "Android Studio installed successfully." ) ) ;
158165 } catch ( error ) {
159166 spinner . fail ( chalk . red ( "Failed to install Android Studio." ) ) ;
@@ -163,28 +170,52 @@ async function installAndroidStudio() {
163170 } else {
164171 spinner . succeed ( chalk . green ( "Android Studio is already installed." ) ) ;
165172 }
173+ } else {
174+ spinner . fail (
175+ chalk . red (
176+ "Please install Android Studio manually on non-Windows systems."
177+ )
178+ ) ;
179+ }
180+ }
166181
182+ /** Function to add Android Studio to PATH */
183+ async function addAndroidStudioToPath ( ) : Promise < void > {
184+ const spinner = ora ( {
185+ text : chalk . blue ( "Adding Android Studio to PATH..." ) ,
186+ } ) . start ( ) ;
187+ spinner . stop ( ) ;
188+
189+ if ( process . platform === "win32" ) {
167190 // Set ANDROID_HOME environment variable
168191 const androidHomePath = path . join (
169192 process . env . ProgramFiles || "C:\\Program Files" ,
170193 "Android" ,
171194 "Sdk"
172195 ) ;
196+
197+ if ( ! fs . existsSync ( androidHomePath ) ) {
198+ spinner . fail (
199+ chalk . red ( "Android SDK not found. Please install Android Studio." )
200+ ) ;
201+ return ;
202+ }
203+
173204 try {
174205 execSync ( `setx ANDROID_HOME "${ androidHomePath } " /M` , {
175206 stdio : "inherit" ,
176207 } ) ;
177208 execSync ( `setx ANDROID_SDK_ROOT "${ androidHomePath } " /M` , {
178209 stdio : "inherit" ,
179210 } ) ;
211+
180212 execSync (
181213 `setx PATH "%PATH%;${ androidHomePath } \\tools;${ androidHomePath } \\platform-tools" /M` ,
182214 { stdio : "inherit" }
183215 ) ;
216+
184217 spinner . succeed (
185- chalk . green (
186- "ANDROID_HOME and ANDROID_SDK_ROOT environment variables set successfully."
187- )
218+ chalk . green ( "Android Studio added to PATH successfully." )
188219 ) ;
189220 } catch ( error ) {
190221 spinner . fail (
@@ -195,17 +226,11 @@ async function installAndroidStudio() {
195226 console . error ( error ) ;
196227 throw error ;
197228 }
198- } else {
199- spinner . fail (
200- chalk . red (
201- "Please install Android Studio manually on non-Windows systems."
202- )
203- ) ;
204229 }
205230}
206231
207- // Function to prompt user for project details
208- async function promptUserForProjectDetails ( ) {
232+ /** Function to prompt user for project details */
233+ async function promptUserForProjectDetails ( ) : Promise < { projectName: string } > {
209234 const questions = [
210235 {
211236 type : "input" ,
@@ -215,19 +240,13 @@ async function promptUserForProjectDetails() {
215240 validate : ( input : string ) =>
216241 input . length > 0 ? true : "Project name cannot be empty." ,
217242 } ,
218- // {
219- // type: "list",
220- // name: "template",
221- // message: "Which template would you like to use?",
222- // choices: ["Default", "TypeScript"],
223- // },
224243 ] ;
225244
226245 return await inquirer . prompt ( questions ) ;
227246}
228247
229- // Function to create a new React Native project
230- async function createReactNativeProject ( projectName : string , template : string ) {
248+ /** Function to create a new React Native project */
249+ async function createReactNativeProject ( projectName : string ) : Promise < void > {
231250 const spinner = ora ( {
232251 text : chalk . blue ( `Creating React Native project "${ projectName } "...` ) ,
233252 } ) . start ( ) ;
@@ -236,21 +255,22 @@ async function createReactNativeProject(projectName: string, template: string) {
236255 execSync ( `npx @react-native-community/cli@latest init ${ projectName } ` , {
237256 stdio : "inherit" ,
238257 } ) ;
258+
239259 spinner . succeed (
240260 chalk . green ( `Project "${ projectName } " created successfully.` )
241261 ) ;
242262
243- spinner . text = chalk . blue (
244- `Installing dependencies and starting the project...`
245- ) ;
246- // Change directory to the project folder
263+ // Change directory and install dependencies
247264 process . chdir ( projectName ) ;
248265
249- // Install dependencies
250- execSync ( "npm install" , { stdio : "inherit" } ) ;
266+ await retry ( async ( ) => {
267+ execSync ( "npm install" , { stdio : "inherit" } ) ;
268+ } ) ;
251269
252270 // Start the project
253- execSync ( "npm run start" , { stdio : "inherit" } ) ;
271+ await retry ( async ( ) => {
272+ execSync ( "npm run start" , { stdio : "inherit" } ) ;
273+ } ) ;
254274
255275 spinner . succeed (
256276 chalk . green ( `Dependencies installed and project started successfully.` )
@@ -261,20 +281,21 @@ async function createReactNativeProject(projectName: string, template: string) {
261281 }
262282}
263283
264- // Main setup function
265- export async function setup ( ) {
284+ /** Main setup function */
285+ export async function setup ( ) : Promise < void > {
266286 console . log ( chalk . cyan ( "Setting up React Native development environment..." ) ) ;
267287
268288 // Check and install necessary tools
269- await installJDK ( ) ;
270- await installChocolatey ( ) ;
271- await installAndroidStudio ( ) ;
289+ await retry ( installChocolatey ) ;
290+ await retry ( installJDK ) ;
291+ await retry ( installAndroidStudio ) ;
292+ await retry ( addAndroidStudioToPath ) ;
272293
273294 // Prompt user for project details
274- const { projectName, template } = await promptUserForProjectDetails ( ) ;
295+ const { projectName } = await promptUserForProjectDetails ( ) ;
275296
276297 // Create the React Native project with user inputs
277- await createReactNativeProject ( projectName , template ) ;
298+ await retry ( ( ) => createReactNativeProject ( projectName ) ) ;
278299
279300 console . log ( chalk . green ( "Setup completed successfully!" ) ) ;
280301}
0 commit comments