@nishant0121/set-it-up 0.0.7 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,210 +1,279 @@
1
- import { execa } from 'execa';
2
- import ora from 'ora';
3
- import chalk from 'chalk';
4
- import fs from 'fs-extra';
5
- import path from 'path';
6
-
7
- // Import templates
8
- import { getNavbar, getLayout } from '../templates/react/components.js';
9
- import { getHome, getAbout } from '../templates/react/pages.js';
10
- import { getApp, getAppContext, getViteConfig } from '../templates/react/main.js';
11
-
12
- export async function setupReact(answers, reactAnswers) {
13
- const spinner = ora('Initializing React project with Vite...').start();
14
- try {
15
- const { projectName, packageManager } = answers;
16
- const isTypescript = reactAnswers.language === 'TypeScript';
17
- // Force TypeScript template if Shadcn is selected, otherwise use user choice
18
- const template = (isTypescript || reactAnswers.addShadcn) ? 'react-ts' : 'react';
19
-
20
- // 1. Scaffold with Vite
21
- await execa('npm', ['create', 'vite@latest', projectName, '--', '--template', template]);
22
-
23
- spinner.text = 'Installing dependencies...';
24
- // 2. Install Dependencies
25
- await execa(packageManager, ['install'], { cwd: projectName });
26
-
27
- // Install Node types for path resolution if TypeScript OR if we forced TS for Shadcn
28
- if (isTypescript || reactAnswers.addShadcn) {
29
- await execa(packageManager, [packageManager === 'npm' ? 'install' : 'add', '-D', '@types/node'], { cwd: projectName });
30
- }
31
-
32
- spinner.text = 'Setting up Tailwind CSS v4...';
33
- // 3. Install Tailwind CSS & Vite Plugin
34
- const installCmd = packageManager === 'npm' ? 'install' : 'add';
35
- await execa(packageManager, [installCmd, 'tailwindcss', '@tailwindcss/vite'], { cwd: projectName });
36
-
37
- // 4. Configure TSConfig for aliases (if TypeScript OR Shadcn forced TS)
38
- if (isTypescript || reactAnswers.addShadcn) {
39
- const tsConfigPath = path.join(projectName, 'tsconfig.json');
40
- const tsConfigAppPath = path.join(projectName, 'tsconfig.app.json');
41
-
42
- const readJsonSafe = async (filePath) => {
43
- const content = await fs.readFile(filePath, 'utf8');
44
- // Simple regex to strip comments (// and /* */)
45
- const jsonContent = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
46
- return JSON.parse(jsonContent);
47
- };
48
-
49
- // Update tsconfig.json
50
- if (await fs.pathExists(tsConfigPath)) {
51
- try {
52
- const tsConfig = await readJsonSafe(tsConfigPath);
53
- tsConfig.compilerOptions = tsConfig.compilerOptions || {};
54
- tsConfig.compilerOptions.baseUrl = ".";
55
- tsConfig.compilerOptions.paths = tsConfig.compilerOptions.paths || {};
56
- tsConfig.compilerOptions.paths["@/*"] = ["./src/*"];
57
-
58
- await fs.writeJson(tsConfigPath, tsConfig, { spaces: 2 });
59
- } catch (e) {
60
- console.warn('Could not update tsconfig.json automatically. Please add baseUrl and paths manually.');
61
- }
62
- }
63
-
64
- // Update tsconfig.app.json
65
- if (await fs.pathExists(tsConfigAppPath)) {
66
- try {
67
- const tsConfigApp = await readJsonSafe(tsConfigAppPath);
68
- tsConfigApp.compilerOptions = tsConfigApp.compilerOptions || {};
69
- tsConfigApp.compilerOptions.baseUrl = ".";
70
- tsConfigApp.compilerOptions.paths = tsConfigApp.compilerOptions.paths || {};
71
- tsConfigApp.compilerOptions.paths["@/*"] = ["./src/*"];
72
-
73
- await fs.writeJson(tsConfigAppPath, tsConfigApp, { spaces: 2 });
74
- } catch (e) {
75
- console.warn('Could not update tsconfig.app.json automatically.');
76
- }
77
- }
78
- }
79
-
80
- // 5. Configure Vite (vite.config.js/ts)
81
- const viteConfigContent = getViteConfig();
82
- const viteConfigPath = path.join(projectName, (isTypescript || reactAnswers.addShadcn) ? 'vite.config.ts' : 'vite.config.js');
83
- await fs.writeFile(viteConfigPath, viteConfigContent);
84
-
85
- // 6. Configure CSS (src/index.css)
86
- const indexCssPath = path.join(projectName, 'src', 'index.css');
87
- await fs.writeFile(indexCssPath, '@import "tailwindcss";');
88
-
89
- // Handle Optional Features
90
- if (reactAnswers.addShadcn) {
91
- spinner.stop();
92
- console.log(chalk.blue('\nšŸŽØ Initializing Shadcn UI...'));
93
-
94
- try {
95
- await execa('npx', ['shadcn@latest', 'init', '-d'], {
96
- cwd: projectName,
97
- stdio: 'inherit'
98
- });
99
-
100
- console.log(chalk.green('āœ” Shadcn UI initialized.'));
101
-
102
- // Add a button component as requested
103
- console.log(chalk.blue('Adding Button component...'));
104
- await execa('npx', ['shadcn@latest', 'add', 'button', '-y'], {
105
- cwd: projectName,
106
- stdio: 'inherit'
107
- });
108
-
109
- } catch (e) {
110
- console.warn(chalk.yellow('⚠ Shadcn UI setup encountered an issue. You might need to run "npx shadcn@latest init" manually.'));
111
- }
112
-
113
- spinner.start();
114
- }
115
-
116
- if (reactAnswers.addRouter) {
117
- spinner.text = 'Installing React Router DOM...';
118
- await execa(packageManager, [installCmd, 'react-router-dom'], { cwd: projectName });
119
- }
120
-
121
- if (reactAnswers.addContext) {
122
- spinner.text = 'Creating AppContext...';
123
- const contextDir = path.join(projectName, 'src', 'context');
124
- await fs.ensureDir(contextDir);
125
-
126
- const contextFile = (isTypescript || reactAnswers.addShadcn) ? 'AppContext.tsx' : 'AppContext.jsx';
127
- const contextContent = getAppContext({ isTypescript, addShadcn: reactAnswers.addShadcn });
128
- await fs.writeFile(path.join(contextDir, contextFile), contextContent);
129
- }
130
-
131
- // Rewrite App.jsx/tsx and create structure
132
- spinner.text = 'Generating Project Structure...';
133
- await generateProjectStructure(projectName, (isTypescript || reactAnswers.addShadcn), reactAnswers);
134
-
135
- // FINAL STEP: Downgrade to JS if requested but forced to TS
136
- if (!isTypescript && reactAnswers.addShadcn) {
137
- spinner.text = 'Converting to JavaScript...';
138
- await convertToJs(projectName);
139
- }
140
-
141
- spinner.succeed(chalk.green(`Project ${projectName} created successfully! šŸš€`));
142
- console.log(chalk.cyan(`
143
- To get started:
144
- cd ${projectName}
145
- ${packageManager} run dev`));
146
-
147
- } catch (error) {
148
- spinner.fail('Setup failed.');
149
- console.error(error);
150
- }
151
- }
152
-
153
- async function generateProjectStructure(projectName, isTypescript, answers) {
154
- const ext = isTypescript ? 'tsx' : 'jsx';
155
- const componentsDir = path.join(projectName, 'src', 'components');
156
- const pagesDir = path.join(projectName, 'src', 'pages');
157
-
158
- await fs.ensureDir(componentsDir);
159
- await fs.ensureDir(pagesDir);
160
-
161
- // 1. Create Navbar
162
- const navbarContent = getNavbar(answers);
163
- await fs.writeFile(path.join(componentsDir, `Navbar.${ext}`), navbarContent);
164
-
165
- // 2. Create Layout (with Outlet)
166
- const layoutContent = getLayout(answers);
167
- await fs.writeFile(path.join(componentsDir, `Layout.${ext}`), layoutContent);
168
-
169
- // 3. Create Pages (Home & About)
170
- const homeContent = getHome(answers);
171
- await fs.writeFile(path.join(pagesDir, `Home.${ext}`), homeContent);
172
-
173
- const aboutContent = getAbout();
174
- await fs.writeFile(path.join(pagesDir, `About.${ext}`), aboutContent);
175
-
176
- // 4. Update App.jsx/tsx
177
- const finalAppContent = getApp(answers);
178
- await fs.writeFile(path.join(projectName, 'src', `App.${ext}`), finalAppContent);
179
- }
180
-
181
- async function convertToJs(projectName) {
182
- const srcDir = path.join(projectName, 'src');
183
-
184
- // Recursive function to rename .tsx -> .jsx and .ts -> .js
185
- async function renameFiles(dir) {
186
- const items = await fs.readdir(dir);
187
- for (const item of items) {
188
- const fullPath = path.join(dir, item);
189
- const stat = await fs.stat(fullPath);
190
-
191
- if (stat.isDirectory()) {
192
- await renameFiles(fullPath);
193
- } else {
194
- if (item.endsWith('.tsx')) {
195
- await fs.rename(fullPath, fullPath.replace('.tsx', '.jsx'));
196
- } else if (item.endsWith('.ts') && !item.endsWith('.d.ts') && item !== 'vite.config.ts') {
197
- // Careful not to rename config files if they are in root (this is in src)
198
- await fs.rename(fullPath, fullPath.replace('.ts', '.js'));
199
- }
200
- }
201
- }
202
- }
203
-
204
- await renameFiles(srcDir);
205
-
206
- // Also rename root files if necessary
207
- const mainTsx = path.join(projectName, 'src', 'main.tsx'); // Standard Vite entry
208
- const mainJsx = path.join(projectName, 'src', 'main.jsx');
209
- if (await fs.pathExists(mainTsx)) await fs.rename(mainTsx, mainJsx);
210
- }
1
+ import { execa } from 'execa';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs-extra';
5
+ import path from 'path';
6
+
7
+ // Import templates
8
+ import { getNavbar, getLayout } from '../templates/react/components.js';
9
+ import { getHome, getAbout } from '../templates/react/pages.js';
10
+ import { getApp, getAppContext, getViteConfig } from '../templates/react/main.js';
11
+
12
+ export async function setupReact(answers, reactAnswers) {
13
+ const spinner = ora('Initializing React project with Vite...').start();
14
+ try {
15
+ const { projectName, packageManager } = answers;
16
+ const isTypescript = reactAnswers.language === 'TypeScript';
17
+ // Force TypeScript template if Shadcn is selected, otherwise use user choice
18
+ const template = (isTypescript || reactAnswers.addShadcn) ? 'react-ts' : 'react';
19
+
20
+ // 1. Scaffold with Vite
21
+ await execa('npm', ['create', 'vite@latest', projectName, '--', '--template', template]);
22
+
23
+ spinner.text = 'Installing dependencies...';
24
+ // 2. Install Dependencies
25
+ await execa(packageManager, ['install'], { cwd: projectName });
26
+
27
+ // Install Node types for path resolution if TypeScript OR if we forced TS for Shadcn
28
+ if (isTypescript || reactAnswers.addShadcn) {
29
+ await execa(packageManager, [packageManager === 'npm' ? 'install' : 'add', '-D', '@types/node'], { cwd: projectName });
30
+ }
31
+
32
+ spinner.text = 'Setting up Tailwind CSS v4...';
33
+ // 3. Install Tailwind CSS & Vite Plugin
34
+ const installCmd = packageManager === 'npm' ? 'install' : 'add';
35
+ await execa(packageManager, [installCmd, 'tailwindcss', '@tailwindcss/vite'], { cwd: projectName });
36
+
37
+ // 4. Configure TSConfig for aliases (if TypeScript OR Shadcn forced TS)
38
+ if (isTypescript || reactAnswers.addShadcn) {
39
+ const tsConfigPath = path.join(projectName, 'tsconfig.json');
40
+ const tsConfigAppPath = path.join(projectName, 'tsconfig.app.json');
41
+
42
+ const readJsonSafe = async (filePath) => {
43
+ const content = await fs.readFile(filePath, 'utf8');
44
+ // Simple regex to strip comments (// and /* */)
45
+ const jsonContent = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
46
+ return JSON.parse(jsonContent);
47
+ };
48
+
49
+ // Update tsconfig.json
50
+ if (await fs.pathExists(tsConfigPath)) {
51
+ try {
52
+ const tsConfig = await readJsonSafe(tsConfigPath);
53
+ tsConfig.compilerOptions = tsConfig.compilerOptions || {};
54
+ tsConfig.compilerOptions.baseUrl = ".";
55
+ tsConfig.compilerOptions.paths = tsConfig.compilerOptions.paths || {};
56
+ tsConfig.compilerOptions.paths["@/*"] = ["./src/*"];
57
+
58
+ await fs.writeJson(tsConfigPath, tsConfig, { spaces: 2 });
59
+ } catch (e) {
60
+ console.warn('Could not update tsconfig.json automatically. Please add baseUrl and paths manually.');
61
+ }
62
+ }
63
+
64
+ // Update tsconfig.app.json
65
+ if (await fs.pathExists(tsConfigAppPath)) {
66
+ try {
67
+ const tsConfigApp = await readJsonSafe(tsConfigAppPath);
68
+ tsConfigApp.compilerOptions = tsConfigApp.compilerOptions || {};
69
+ tsConfigApp.compilerOptions.baseUrl = ".";
70
+ tsConfigApp.compilerOptions.paths = tsConfigApp.compilerOptions.paths || {};
71
+ tsConfigApp.compilerOptions.paths["@/*"] = ["./src/*"];
72
+
73
+ await fs.writeJson(tsConfigAppPath, tsConfigApp, { spaces: 2 });
74
+ } catch (e) {
75
+ console.warn('Could not update tsconfig.app.json automatically.');
76
+ }
77
+ }
78
+ }
79
+
80
+ // 5. Configure Vite (vite.config.js/ts)
81
+ const viteConfigContent = getViteConfig();
82
+ const viteConfigPath = path.join(projectName, (isTypescript || reactAnswers.addShadcn) ? 'vite.config.ts' : 'vite.config.js');
83
+ await fs.writeFile(viteConfigPath, viteConfigContent);
84
+
85
+ // 6. Configure CSS (src/index.css)
86
+ const indexCssPath = path.join(projectName, 'src', 'index.css');
87
+ await fs.writeFile(indexCssPath, '@import "tailwindcss";');
88
+
89
+ // Handle Optional Features
90
+ if (reactAnswers.addShadcn) {
91
+ spinner.stop();
92
+ console.log(chalk.blue('\nšŸŽØ Initializing Shadcn UI...'));
93
+
94
+ try {
95
+ await execa('npx', ['shadcn@latest', 'init', '-d'], {
96
+ cwd: projectName,
97
+ stdio: 'inherit'
98
+ });
99
+
100
+ console.log(chalk.green('āœ” Shadcn UI initialized.'));
101
+
102
+ // Add a button component as requested
103
+ console.log(chalk.blue('Adding Button component...'));
104
+ await execa('npx', ['shadcn@latest', 'add', 'button', '-y'], {
105
+ cwd: projectName,
106
+ stdio: 'inherit'
107
+ });
108
+
109
+ } catch (e) {
110
+ console.warn(chalk.yellow('⚠ Shadcn UI setup encountered an issue. You might need to run "npx shadcn@latest init" manually.'));
111
+ }
112
+
113
+ spinner.start();
114
+ }
115
+
116
+ if (reactAnswers.addRouter) {
117
+ spinner.text = 'Installing React Router DOM...';
118
+ await execa(packageManager, [installCmd, 'react-router-dom'], { cwd: projectName });
119
+ }
120
+
121
+ if (reactAnswers.addContext) {
122
+ spinner.text = 'Creating AppContext...';
123
+ const contextDir = path.join(projectName, 'src', 'context');
124
+ await fs.ensureDir(contextDir);
125
+
126
+ const contextFile = (isTypescript || reactAnswers.addShadcn) ? 'AppContext.tsx' : 'AppContext.jsx';
127
+ const contextContent = getAppContext({ isTypescript, addShadcn: reactAnswers.addShadcn });
128
+ await fs.writeFile(path.join(contextDir, contextFile), contextContent);
129
+ }
130
+
131
+ // Rewrite App.jsx/tsx and create structure
132
+ spinner.text = 'Generating Project Structure...';
133
+ await generateProjectStructure(projectName, isTypescript, reactAnswers);
134
+
135
+ // FINAL STEP: Downgrade to JS if requested but forced to TS
136
+ if (!isTypescript && reactAnswers.addShadcn) {
137
+ spinner.text = 'Converting to JavaScript...';
138
+ await convertToJs(projectName);
139
+ }
140
+
141
+ spinner.succeed(chalk.green(`Project ${projectName} created successfully! šŸš€`));
142
+ console.log(chalk.cyan(`
143
+ To get started:
144
+ cd ${projectName}
145
+ ${packageManager} run dev`));
146
+
147
+ } catch (error) {
148
+ spinner.fail('Setup failed.');
149
+ console.error(error);
150
+ }
151
+ }
152
+
153
+ async function generateProjectStructure(projectName, isTypescript, answers) {
154
+ const ext = isTypescript ? 'tsx' : 'jsx';
155
+ const componentsDir = path.join(projectName, 'src', 'components');
156
+ const pagesDir = path.join(projectName, 'src', 'pages');
157
+
158
+ await fs.ensureDir(componentsDir);
159
+ await fs.ensureDir(pagesDir);
160
+
161
+ // 1. Create Navbar
162
+ const navbarContent = getNavbar(answers);
163
+ await fs.writeFile(path.join(componentsDir, `Navbar.${ext}`), navbarContent);
164
+
165
+ // 2. Create Layout (with Outlet)
166
+ const layoutContent = getLayout(answers);
167
+ await fs.writeFile(path.join(componentsDir, `Layout.${ext}`), layoutContent);
168
+
169
+ // 3. Create Pages (Home & About)
170
+ const homeContent = getHome(answers);
171
+ await fs.writeFile(path.join(pagesDir, `Home.${ext}`), homeContent);
172
+
173
+ const aboutContent = getAbout();
174
+ await fs.writeFile(path.join(pagesDir, `About.${ext}`), aboutContent);
175
+
176
+ // 4. Update App.jsx/tsx
177
+ const finalAppContent = getApp(answers);
178
+ await fs.writeFile(path.join(projectName, 'src', `App.${ext}`), finalAppContent);
179
+ }
180
+
181
+ async function convertToJs(projectName) {
182
+ const srcDir = path.join(projectName, 'src');
183
+
184
+ // 1. Handle main.tsx -> main.jsx
185
+ const mainTsx = path.join(srcDir, 'main.tsx');
186
+ const mainJsx = path.join(srcDir, 'main.jsx');
187
+
188
+ if (await fs.pathExists(mainTsx)) {
189
+ try {
190
+ await execa('npx', [
191
+ 'esbuild',
192
+ mainTsx,
193
+ '--jsx=preserve',
194
+ `--outfile=${mainJsx}`,
195
+ '--format=esm'
196
+ ], { cwd: process.cwd() });
197
+ await fs.remove(mainTsx);
198
+
199
+ // Fix imports in main.jsx (esbuild preserves local imports)
200
+ let mainContent = await fs.readFile(mainJsx, 'utf8');
201
+ mainContent = mainContent.replace(/from\s+['"]\.\/App\.tsx['"]/g, 'from "./App"');
202
+ await fs.writeFile(mainJsx, mainContent);
203
+
204
+ } catch (e) {
205
+ console.warn(`Failed to convert main.tsx: ${e.message}`);
206
+ }
207
+ }
208
+
209
+ // 2. Handle App.tsx (Delete if App.jsx exists, otherwise convert)
210
+ const appTsx = path.join(srcDir, 'App.tsx');
211
+ const appJsx = path.join(srcDir, 'App.jsx');
212
+
213
+ if (await fs.pathExists(appTsx)) {
214
+ if (await fs.pathExists(appJsx)) {
215
+ // We generated a custom App.jsx, so the default App.tsx is garbage.
216
+ await fs.remove(appTsx);
217
+ } else {
218
+ // Fallback: convert App.tsx if we didn't generate App.jsx
219
+ try {
220
+ await execa('npx', [
221
+ 'esbuild',
222
+ appTsx,
223
+ '--jsx=preserve',
224
+ `--outfile=${appJsx}`,
225
+ '--format=esm'
226
+ ], { cwd: process.cwd() });
227
+ await fs.remove(appTsx);
228
+ } catch (e) {
229
+ console.warn(`Failed to convert App.tsx: ${e.message}`);
230
+ }
231
+ }
232
+ }
233
+
234
+ // 3. Remove vite-env.d.ts
235
+ const viteEnv = path.join(srcDir, 'vite-env.d.ts');
236
+ if (await fs.pathExists(viteEnv)) {
237
+ await fs.remove(viteEnv);
238
+ }
239
+
240
+ // 4. Handle vite.config.ts -> vite.config.js
241
+ const viteConfigTs = path.join(projectName, 'vite.config.ts');
242
+ const viteConfigJs = path.join(projectName, 'vite.config.js');
243
+
244
+ if (await fs.pathExists(viteConfigTs)) {
245
+ try {
246
+ await execa('npx', [
247
+ 'esbuild',
248
+ viteConfigTs,
249
+ `--outfile=${viteConfigJs}`,
250
+ '--format=esm'
251
+ ], { cwd: process.cwd() });
252
+ await fs.remove(viteConfigTs);
253
+ } catch (e) {
254
+ console.warn(`Failed to convert vite.config.ts: ${e.message}`);
255
+ }
256
+ }
257
+
258
+ // Update index.html to reference main.jsx
259
+ const indexHtmlPath = path.join(projectName, 'index.html');
260
+ if (await fs.pathExists(indexHtmlPath)) {
261
+ let indexHtml = await fs.readFile(indexHtmlPath, 'utf8');
262
+ indexHtml = indexHtml.replace('/src/main.tsx', '/src/main.jsx');
263
+ await fs.writeFile(indexHtmlPath, indexHtml);
264
+ }
265
+
266
+ // Clean up TS configs and create jsconfig.json
267
+ await fs.remove(path.join(projectName, 'tsconfig.json'));
268
+ await fs.remove(path.join(projectName, 'tsconfig.app.json'));
269
+ await fs.remove(path.join(projectName, 'tsconfig.node.json'));
270
+
271
+ const jsConfig = {
272
+ "compilerOptions": {
273
+ "paths": {
274
+ "@/*": ["./src/*"]
275
+ }
276
+ }
277
+ };
278
+ await fs.writeJson(path.join(projectName, 'jsconfig.json'), jsConfig, { spaces: 2 });
279
+ }
@@ -1,78 +1,78 @@
1
- import { execa } from 'execa';
2
- import ora from 'ora';
3
- import chalk from 'chalk';
4
- import fs from 'fs-extra';
5
- import path from 'path';
6
- import { fileURLToPath } from 'url';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- export async function setupReactNative(answers, rnAnswers) {
12
- const spinner = ora('Initializing React Native project...').start();
13
- try {
14
- const { projectName, packageManager } = answers;
15
- const isTypescript = rnAnswers.language === 'TypeScript';
16
-
17
- // Basic init command using the community CLI for latest version
18
- const args = ['--yes', '@react-native-community/cli@latest', 'init', projectName, '--skip-install'];
19
-
20
- await execa('npx', args);
21
-
22
- // Handle language selection (rename App.tsx to App.jsx if JS is selected)
23
- const appTsxPath = path.join(projectName, 'App.tsx');
24
- const appJsxPath = path.join(projectName, 'App.jsx');
25
-
26
- if (!isTypescript && await fs.pathExists(appTsxPath)) {
27
- await fs.rename(appTsxPath, appJsxPath);
28
- }
29
-
30
- spinner.text = 'Installing dependencies...';
31
-
32
- // Install dependencies using the selected package manager
33
- await execa(packageManager, ['install'], { cwd: projectName });
34
-
35
- if (rnAnswers.addNavigation) {
36
- spinner.text = 'Installing React Navigation...';
37
- const installCmd = packageManager === 'npm' ? 'install' : 'add';
38
- const packages = [
39
- '@react-navigation/native',
40
- 'react-native-screens',
41
- 'react-native-safe-area-context',
42
- '@react-navigation/native-stack'
43
- ];
44
-
45
- await execa(packageManager, [installCmd, ...packages], { cwd: projectName });
46
-
47
- spinner.text = 'Configuring Navigation...';
48
-
49
- // Create modular folder structure
50
- const srcDir = path.join(projectName, 'src');
51
- const pagesDir = path.join(srcDir, 'pages');
52
- const componentsDir = path.join(srcDir, 'components');
53
-
54
- await fs.ensureDir(pagesDir);
55
- await fs.ensureDir(componentsDir);
56
-
57
- const ext = isTypescript ? 'tsx' : 'jsx';
58
- const templateBase = path.join(__dirname, '..', 'templates', 'reactNative', 'modular');
59
-
60
- // Copy App file
61
- const appContent = await fs.readFile(path.join(templateBase, `App.${ext}`), 'utf8');
62
- const targetAppPath = isTypescript ? appTsxPath : appJsxPath;
63
- await fs.writeFile(targetAppPath, appContent);
64
-
65
- // Copy Screens
66
- const homeContent = await fs.readFile(path.join(templateBase, 'pages', `HomeScreen.${ext}`), 'utf8');
67
- await fs.writeFile(path.join(pagesDir, `HomeScreen.${ext}`), homeContent);
68
-
69
- const detailsContent = await fs.readFile(path.join(templateBase, 'pages', `DetailsScreen.${ext}`), 'utf8');
70
- await fs.writeFile(path.join(pagesDir, `DetailsScreen.${ext}`), detailsContent);
71
- }
72
-
73
- spinner.succeed(chalk.green(`Project ${projectName} created successfully! šŸš€`));
74
- } catch (error) {
75
- spinner.fail('Setup failed.');
76
- console.error(error);
77
- }
1
+ import { execa } from 'execa';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs-extra';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ export async function setupReactNative(answers, rnAnswers) {
12
+ const spinner = ora('Initializing React Native project...').start();
13
+ try {
14
+ const { projectName, packageManager } = answers;
15
+ const isTypescript = rnAnswers.language === 'TypeScript';
16
+
17
+ // Basic init command using the community CLI for latest version
18
+ const args = ['--yes', '@react-native-community/cli@latest', 'init', projectName, '--skip-install'];
19
+
20
+ await execa('npx', args);
21
+
22
+ // Handle language selection (rename App.tsx to App.jsx if JS is selected)
23
+ const appTsxPath = path.join(projectName, 'App.tsx');
24
+ const appJsxPath = path.join(projectName, 'App.jsx');
25
+
26
+ if (!isTypescript && await fs.pathExists(appTsxPath)) {
27
+ await fs.rename(appTsxPath, appJsxPath);
28
+ }
29
+
30
+ spinner.text = 'Installing dependencies...';
31
+
32
+ // Install dependencies using the selected package manager
33
+ await execa(packageManager, ['install'], { cwd: projectName });
34
+
35
+ if (rnAnswers.addNavigation) {
36
+ spinner.text = 'Installing React Navigation...';
37
+ const installCmd = packageManager === 'npm' ? 'install' : 'add';
38
+ const packages = [
39
+ '@react-navigation/native',
40
+ 'react-native-screens',
41
+ 'react-native-safe-area-context',
42
+ '@react-navigation/native-stack'
43
+ ];
44
+
45
+ await execa(packageManager, [installCmd, ...packages], { cwd: projectName });
46
+
47
+ spinner.text = 'Configuring Navigation...';
48
+
49
+ // Create modular folder structure
50
+ const srcDir = path.join(projectName, 'src');
51
+ const pagesDir = path.join(srcDir, 'pages');
52
+ const componentsDir = path.join(srcDir, 'components');
53
+
54
+ await fs.ensureDir(pagesDir);
55
+ await fs.ensureDir(componentsDir);
56
+
57
+ const ext = isTypescript ? 'tsx' : 'jsx';
58
+ const templateBase = path.join(__dirname, '..', 'templates', 'reactNative', 'modular');
59
+
60
+ // Copy App file
61
+ const appContent = await fs.readFile(path.join(templateBase, `App.${ext}`), 'utf8');
62
+ const targetAppPath = isTypescript ? appTsxPath : appJsxPath;
63
+ await fs.writeFile(targetAppPath, appContent);
64
+
65
+ // Copy Screens
66
+ const homeContent = await fs.readFile(path.join(templateBase, 'pages', `HomeScreen.${ext}`), 'utf8');
67
+ await fs.writeFile(path.join(pagesDir, `HomeScreen.${ext}`), homeContent);
68
+
69
+ const detailsContent = await fs.readFile(path.join(templateBase, 'pages', `DetailsScreen.${ext}`), 'utf8');
70
+ await fs.writeFile(path.join(pagesDir, `DetailsScreen.${ext}`), detailsContent);
71
+ }
72
+
73
+ spinner.succeed(chalk.green(`Project ${projectName} created successfully! šŸš€`));
74
+ } catch (error) {
75
+ spinner.fail('Setup failed.');
76
+ console.error(error);
77
+ }
78
78
  }