@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.
- package/DESCRIPTION.md +64 -0
- package/README.md +75 -75
- package/bin/index.js +22 -22
- package/package.json +2 -1
- package/src/engines/express.js +86 -0
- package/src/engines/react.js +279 -210
- package/src/engines/reactNative.js +77 -77
- package/src/templates/express/configuration.js +63 -0
- package/src/templates/express/controllers.js +9 -0
- package/src/templates/express/entry.js +42 -0
- package/src/templates/express/main.js +4 -0
- package/src/templates/express/routes.js +11 -0
- package/src/templates/react/main.js +2 -2
- package/src/wizard.js +136 -123
package/src/engines/react.js
CHANGED
|
@@ -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,
|
|
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
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
}
|