-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcli.js
executable file
·186 lines (156 loc) · 6.22 KB
/
cli.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env node
import { exec } from 'child_process';
import path from 'path';
import fs from 'fs';
import ora from 'ora';
import chalk from 'chalk';
import { fileURLToPath } from 'url';
import inquirer from 'inquirer';
import figlet from 'figlet';
// Utility to execute shell commands asynchronously
const runCommandAsync = (command) => {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
resolve();
});
});
};
// Function to check if VSCode is installed
const isVSCodeInstalled = () => {
return new Promise((resolve) => {
exec('code --version', (error) => {
resolve(!error);
});
});
};
// Prompt the user for a project name if not provided
const promptProjectName = async () => {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'repoName',
message: 'Enter the project name:',
validate: (input) => (input.trim() !== '' ? true : 'Project name cannot be empty'),
},
]);
return answers.repoName;
};
const updatePackageJsonName = (projectPath, newName) => {
const packageJsonPath = path.join(projectPath, 'package.json');
// Check if the package.json file exists
if (!fs.existsSync(packageJsonPath)) {
console.error(chalk.red(`❌ Error: No package.json found in ${projectPath}`));
return;
}
// Read the package.json file
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
const packageJsonData = JSON.parse(packageJsonContent);
// Modify the "name" field
packageJsonData.name = newName;
// Write the updated content back to package.json
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJsonData, null, 2));
};
// Main project creation function
const createProject = async () => {
let repoName = process.argv[2];
// Ask for the project name if not provided
if (!repoName) {
repoName = await promptProjectName();
}
const currentPath = process.cwd();
const projectPath = path.join(currentPath, repoName);
if (fs.existsSync(projectPath)) {
console.error(chalk.red(`❌ Error: The directory "${repoName}" already exists in the current path.`));
process.exit(1);
}
// Welcome message with ASCII art
console.log(
chalk.blue(figlet.textSync('Node Starter', { horizontalLayout: 'full' }))
);
console.log(chalk.cyan(`🚀 Creating a new Node.js project in ${chalk.green(projectPath)}...\n`));
const gitCloneCommand = `git clone --depth 1 https://github.com/MunavvarSinan/node-starter ${repoName}`;
const installDepsCommand = `cd ${repoName} && npm install`;
// Step 1: Clone the repository (suppressing logs)
const spinner = ora({
text: 'Creating magic... This may take a moment!',
spinner: 'moon', // Keeping the original moon spinner
}).start();
try {
await runCommandAsync(gitCloneCommand);
updatePackageJsonName(projectPath, repoName);
spinner.succeed(chalk.green('✨ Project files have arrived from the magic vault!\n'));
} catch (error) {
spinner.fail(chalk.red('🚨 Failed to clone the repository. Something interrupted the magic.'));
process.exit(1);
}
// Step 2: Install dependencies
spinner.text = 'Installing dependencies...';
spinner.start();
try {
await runCommandAsync(installDepsCommand);
spinner.succeed(chalk.green('🎉 All dependencies brewed successfully!\n'));
} catch (error) {
spinner.fail(chalk.red('⚠️ Failed to install dependencies. Something might be wrong with npm.'));
process.exit(1);
}
// Step 3: Ask if the user wants to initialize a new Git repository
const { initializeGit } = await inquirer.prompt([
{
type: 'confirm',
name: 'initializeGit',
message: 'Would you like to initialize a new Git repository?',
default: true,
},
]);
if (initializeGit) {
spinner.text = 'Initializing a new Git repository...';
spinner.start();
try {
await runCommandAsync(`cd ${repoName} && rm -rf .git && git init`);
spinner.succeed(chalk.green('📝 Git repository successfully initialized.\n'));
} catch (error) {
spinner.fail(chalk.red('Failed to initialize Git repository.'));
}
}
// Step 4: Ask if the user wants to open the project folder (with VSCode support)
const { openProject } = await inquirer.prompt([
{
type: 'confirm',
name: 'openProject',
message: 'Would you like to open the project folder now?',
default: false,
},
]);
if (openProject) {
spinner.text = 'Checking for VSCode...';
spinner.start();
try {
const isVSCodeAvailable = await isVSCodeInstalled();
if (isVSCodeAvailable) {
spinner.text = 'VSCode detected! Opening project in VSCode...';
await runCommandAsync(`code ${repoName}`);
spinner.succeed(chalk.green('💻 Project opened in VSCode!\n'));
} else {
spinner.text = 'VSCode not detected. Opening the project folder...';
const openCommand = process.platform === 'darwin' ? `open ${repoName}` : process.platform === 'win32' ? `start ${repoName}` : `xdg-open ${repoName}`;
await runCommandAsync(openCommand);
spinner.succeed(chalk.green('📂 Project folder is now open!\n'));
}
} catch (error) {
spinner.fail(chalk.red('🚪 Could not open the project folder. Please open it manually.'));
}
}
// Step 5: Display final instructions
console.log(chalk.green('\n🎉 Your project is ready!'));
console.log(chalk.cyan('\nTo start your project, run the following commands:'));
console.log(chalk.yellow(`cd ${repoName} && docker compose up`));
};
// Execute the main function and handle any unexpected errors
createProject().catch((error) => {
console.error(chalk.red('An unexpected error occurred:'), error);
process.exit(1);
});