@jatinmourya/ng-init 1.0.0
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/CHANGELOG.md +129 -0
- package/CONTRIBUTING.md +210 -0
- package/IMPLEMENTATION_SUMMARY.md +411 -0
- package/INSTALLATION.md +375 -0
- package/LICENSE +21 -0
- package/PROJECT_DOCUMENTATION.md +384 -0
- package/QUICK_START.md +252 -0
- package/README.md +300 -0
- package/package.json +56 -0
- package/src/index.js +152 -0
- package/src/runner.js +574 -0
- package/src/templates/templates.js +403 -0
- package/src/utils/compatibility.js +333 -0
- package/src/utils/file-utils.js +232 -0
- package/src/utils/installer.js +247 -0
- package/src/utils/npm-search.js +354 -0
- package/src/utils/profile-manager.js +219 -0
- package/src/utils/prompt-handler.js +393 -0
- package/src/utils/version-checker.js +169 -0
package/src/runner.js
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { displaySystemVersions, getNodeVersion, isNvmInstalled, switchNodeVersion, installNodeVersion, getInstalledNodeVersions } from './utils/version-checker.js';
|
|
5
|
+
import { getAngularVersions, getNodeRequirementsForAngular, getMajorVersions, getMinorVersionsForMajor, getPatchVersionsForMinor } from './utils/npm-search.js';
|
|
6
|
+
import { checkNodeCompatibility, displayCompatibilityStatus, findCompatibleVersions, getRecommendedNodeVersion, resolveLibraryVersions } from './utils/compatibility.js';
|
|
7
|
+
import { createAngularProject, installPackages, runNpmInstall, installNodeWithWinget, displayNvmInstallGuide } from './utils/installer.js';
|
|
8
|
+
import { interactiveLibrarySearch, simpleLibraryInput, askLibrarySearchPreference } from './utils/prompt-handler.js';
|
|
9
|
+
import { PROJECT_TEMPLATES, LIBRARY_BUNDLES, CONFIG_PRESETS, PROJECT_STRUCTURE, GIT_CONFIG, DOC_TEMPLATES } from './templates/templates.js';
|
|
10
|
+
import { initGitRepo, createGitignore, createInitialCommit, createProjectFolders, createProjectFiles, createReadme, createChangelog, validateDirectoryName, ensureDirectory, updatePackageJsonScripts } from './utils/file-utils.js';
|
|
11
|
+
import { saveProfile, loadProfile, listProfiles, displayProfileInfo } from './utils/profile-manager.js';
|
|
12
|
+
|
|
13
|
+
export async function runCli() {
|
|
14
|
+
try {
|
|
15
|
+
// Display welcome banner
|
|
16
|
+
console.log(chalk.bold.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
17
|
+
console.log(chalk.bold.cyan('║ Angular Project Automation CLI v1.0.0 ║'));
|
|
18
|
+
console.log(chalk.bold.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
19
|
+
|
|
20
|
+
// Step 1: Display system versions
|
|
21
|
+
const systemVersions = await displaySystemVersions();
|
|
22
|
+
|
|
23
|
+
// Step 2: Check for saved profiles
|
|
24
|
+
const useProfile = await inquirer.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'confirm',
|
|
27
|
+
name: 'use',
|
|
28
|
+
message: 'Would you like to use a saved profile?',
|
|
29
|
+
default: false
|
|
30
|
+
}
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
let config = {};
|
|
34
|
+
|
|
35
|
+
if (useProfile.use) {
|
|
36
|
+
const profiles = await listProfiles();
|
|
37
|
+
|
|
38
|
+
if (profiles.length === 0) {
|
|
39
|
+
console.log(chalk.yellow('No saved profiles found. Continuing with manual setup...\n'));
|
|
40
|
+
} else {
|
|
41
|
+
const profileAnswer = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
type: 'list',
|
|
44
|
+
name: 'profile',
|
|
45
|
+
message: 'Select a profile:',
|
|
46
|
+
choices: profiles
|
|
47
|
+
}
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
const profile = await loadProfile(profileAnswer.profile);
|
|
51
|
+
displayProfileInfo(profileAnswer.profile, profile);
|
|
52
|
+
|
|
53
|
+
const confirmProfile = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'confirm',
|
|
56
|
+
name: 'confirm',
|
|
57
|
+
message: 'Use this profile?',
|
|
58
|
+
default: true
|
|
59
|
+
}
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
if (confirmProfile.confirm) {
|
|
63
|
+
config = profile;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Step 3: Select Angular version (if not from profile)
|
|
69
|
+
if (!config.angularVersion) {
|
|
70
|
+
console.log(chalk.bold.cyan('\n📦 Fetching Angular versions...\n'));
|
|
71
|
+
const angularVersions = await getAngularVersions();
|
|
72
|
+
|
|
73
|
+
if (angularVersions.versions.length === 0) {
|
|
74
|
+
console.log(chalk.red('Failed to fetch Angular versions. Please check your internet connection.'));
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Step 3.1: Select Major Version
|
|
79
|
+
const majorVersions = getMajorVersions(angularVersions.versions);
|
|
80
|
+
const majorChoices = majorVersions.map(major => {
|
|
81
|
+
const label = `Angular ${major}`;
|
|
82
|
+
// Check if this major version contains the latest
|
|
83
|
+
const isLatest = angularVersions.latest && angularVersions.latest.startsWith(`${major}.`);
|
|
84
|
+
return {
|
|
85
|
+
name: isLatest ? `${label} (latest)` : label,
|
|
86
|
+
value: major
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const majorAnswer = await inquirer.prompt([
|
|
91
|
+
{
|
|
92
|
+
type: 'list',
|
|
93
|
+
name: 'major',
|
|
94
|
+
message: 'Select Angular major version:',
|
|
95
|
+
choices: majorChoices,
|
|
96
|
+
pageSize: 15
|
|
97
|
+
}
|
|
98
|
+
]);
|
|
99
|
+
|
|
100
|
+
// Step 3.2: Select Minor Version
|
|
101
|
+
const minorVersions = getMinorVersionsForMajor(angularVersions.versions, majorAnswer.major);
|
|
102
|
+
const minorChoices = minorVersions.map(minor => ({
|
|
103
|
+
name: `v${minor}.x`,
|
|
104
|
+
value: minor
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
const minorAnswer = await inquirer.prompt([
|
|
108
|
+
{
|
|
109
|
+
type: 'list',
|
|
110
|
+
name: 'minor',
|
|
111
|
+
message: `Select Angular ${majorAnswer.major} minor version:`,
|
|
112
|
+
choices: minorChoices,
|
|
113
|
+
pageSize: 15
|
|
114
|
+
}
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
// Step 3.3: Select Patch Version
|
|
118
|
+
const patchVersions = getPatchVersionsForMinor(angularVersions.versions, minorAnswer.minor);
|
|
119
|
+
const patchChoices = patchVersions.map(patch => {
|
|
120
|
+
let label = `v${patch}`;
|
|
121
|
+
if (patch === angularVersions.latest) label += ' (latest)';
|
|
122
|
+
if (patch === angularVersions.lts) label += ' (LTS)';
|
|
123
|
+
return { name: label, value: patch };
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const patchAnswer = await inquirer.prompt([
|
|
127
|
+
{
|
|
128
|
+
type: 'list',
|
|
129
|
+
name: 'patch',
|
|
130
|
+
message: `Select Angular ${minorAnswer.minor} patch version:`,
|
|
131
|
+
choices: patchChoices,
|
|
132
|
+
pageSize: 15
|
|
133
|
+
}
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
config.angularVersion = patchAnswer.patch;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(chalk.green(`\n✓ Selected Angular version: ${config.angularVersion}\n`));
|
|
140
|
+
|
|
141
|
+
// Step 4: Check Node.js compatibility
|
|
142
|
+
const nodeRequirement = await getNodeRequirementsForAngular(config.angularVersion);
|
|
143
|
+
const currentNodeVersion = await getNodeVersion();
|
|
144
|
+
const compatibility = checkNodeCompatibility(currentNodeVersion, nodeRequirement);
|
|
145
|
+
|
|
146
|
+
displayCompatibilityStatus(compatibility);
|
|
147
|
+
|
|
148
|
+
// Step 5: Handle Node version incompatibility
|
|
149
|
+
if (!compatibility.compatible) {
|
|
150
|
+
console.log(chalk.yellow('⚠️ Node.js version incompatibility detected!\n'));
|
|
151
|
+
|
|
152
|
+
const nvmInstalled = await isNvmInstalled();
|
|
153
|
+
|
|
154
|
+
if (nvmInstalled) {
|
|
155
|
+
console.log(chalk.cyan('✓ nvm detected on your system\n'));
|
|
156
|
+
|
|
157
|
+
const installedVersions = await getInstalledNodeVersions();
|
|
158
|
+
const compatibleInstalled = findCompatibleVersions(installedVersions, nodeRequirement);
|
|
159
|
+
|
|
160
|
+
if (compatibleInstalled.length > 0) {
|
|
161
|
+
console.log(chalk.green(`Found ${compatibleInstalled.length} compatible Node version(s) installed:\n`));
|
|
162
|
+
|
|
163
|
+
const switchAnswer = await inquirer.prompt([
|
|
164
|
+
{
|
|
165
|
+
type: 'list',
|
|
166
|
+
name: 'version',
|
|
167
|
+
message: 'Select Node version to switch to:',
|
|
168
|
+
choices: compatibleInstalled.map(v => ({ name: `v${v}`, value: v }))
|
|
169
|
+
}
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
console.log(chalk.cyan(`\nSwitching to Node.js v${switchAnswer.version}...\n`));
|
|
173
|
+
const switched = await switchNodeVersion(switchAnswer.version);
|
|
174
|
+
|
|
175
|
+
if (!switched) {
|
|
176
|
+
console.log(chalk.red('Failed to switch Node version. Please try manually.'));
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.log(chalk.green('✓ Node version switched successfully\n'));
|
|
181
|
+
} else {
|
|
182
|
+
console.log(chalk.yellow('No compatible Node versions installed.\n'));
|
|
183
|
+
const recommendedVersion = getRecommendedNodeVersion(nodeRequirement);
|
|
184
|
+
|
|
185
|
+
const installAnswer = await inquirer.prompt([
|
|
186
|
+
{
|
|
187
|
+
type: 'confirm',
|
|
188
|
+
name: 'install',
|
|
189
|
+
message: `Install Node.js v${recommendedVersion}?`,
|
|
190
|
+
default: true
|
|
191
|
+
}
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
if (installAnswer.install) {
|
|
195
|
+
const installed = await installNodeVersion(recommendedVersion);
|
|
196
|
+
|
|
197
|
+
if (!installed) {
|
|
198
|
+
console.log(chalk.red('Failed to install Node version.'));
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log(chalk.green('✓ Node.js installed successfully\n'));
|
|
203
|
+
await switchNodeVersion(recommendedVersion);
|
|
204
|
+
} else {
|
|
205
|
+
console.log(chalk.red('Cannot proceed without compatible Node.js version.'));
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
console.log(chalk.yellow('⚠️ nvm is not installed on your system\n'));
|
|
211
|
+
|
|
212
|
+
const installChoice = await inquirer.prompt([
|
|
213
|
+
{
|
|
214
|
+
type: 'list',
|
|
215
|
+
name: 'method',
|
|
216
|
+
message: 'How would you like to proceed?',
|
|
217
|
+
choices: [
|
|
218
|
+
{ name: 'Install nvm (Recommended)', value: 'nvm' },
|
|
219
|
+
{ name: 'Install Node.js directly (Windows only)', value: 'direct' },
|
|
220
|
+
{ name: 'Exit and install manually', value: 'exit' }
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
if (installChoice.method === 'nvm') {
|
|
226
|
+
displayNvmInstallGuide();
|
|
227
|
+
console.log(chalk.yellow('\nPlease install nvm and run this CLI again.\n'));
|
|
228
|
+
process.exit(0);
|
|
229
|
+
} else if (installChoice.method === 'direct') {
|
|
230
|
+
if (process.platform !== 'win32') {
|
|
231
|
+
console.log(chalk.red('Direct installation is only supported on Windows.'));
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const installed = await installNodeWithWinget('LTS');
|
|
236
|
+
|
|
237
|
+
if (!installed) {
|
|
238
|
+
console.log(chalk.red('Failed to install Node.js. Please install manually.'));
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log(chalk.yellow('\nPlease restart your terminal and run this CLI again.\n'));
|
|
243
|
+
process.exit(0);
|
|
244
|
+
} else {
|
|
245
|
+
console.log(chalk.yellow('Exiting. Please install a compatible Node.js version manually.\n'));
|
|
246
|
+
process.exit(0);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Step 6: Project configuration
|
|
252
|
+
if (!config.projectName) {
|
|
253
|
+
const projectAnswer = await inquirer.prompt([
|
|
254
|
+
{
|
|
255
|
+
type: 'input',
|
|
256
|
+
name: 'name',
|
|
257
|
+
message: 'Enter project name:',
|
|
258
|
+
validate: (value) => {
|
|
259
|
+
if (!value) return 'Project name is required';
|
|
260
|
+
const validation = validateDirectoryName(value);
|
|
261
|
+
return validation === true ? true : validation;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
]);
|
|
265
|
+
|
|
266
|
+
config.projectName = projectAnswer.name;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Step 7: Project location
|
|
270
|
+
if (!config.location) {
|
|
271
|
+
const locationAnswer = await inquirer.prompt([
|
|
272
|
+
{
|
|
273
|
+
type: 'list',
|
|
274
|
+
name: 'location',
|
|
275
|
+
message: 'Where would you like to create the project?',
|
|
276
|
+
choices: [
|
|
277
|
+
{ name: 'Current directory', value: 'current' },
|
|
278
|
+
{ name: 'Specify custom directory', value: 'custom' }
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
]);
|
|
282
|
+
|
|
283
|
+
if (locationAnswer.location === 'custom') {
|
|
284
|
+
const customPath = await inquirer.prompt([
|
|
285
|
+
{
|
|
286
|
+
type: 'input',
|
|
287
|
+
name: 'path',
|
|
288
|
+
message: 'Enter directory path:',
|
|
289
|
+
default: process.cwd()
|
|
290
|
+
}
|
|
291
|
+
]);
|
|
292
|
+
|
|
293
|
+
config.location = customPath.path;
|
|
294
|
+
} else {
|
|
295
|
+
config.location = process.cwd();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const projectPath = path.join(config.location, config.projectName);
|
|
300
|
+
|
|
301
|
+
// Step 8: Select template (if not from profile)
|
|
302
|
+
if (!config.template) {
|
|
303
|
+
const templateAnswer = await inquirer.prompt([
|
|
304
|
+
{
|
|
305
|
+
type: 'list',
|
|
306
|
+
name: 'template',
|
|
307
|
+
message: 'Select project template:',
|
|
308
|
+
choices: [
|
|
309
|
+
...Object.entries(PROJECT_TEMPLATES).map(([key, template]) => ({
|
|
310
|
+
name: `${template.name} - ${template.description}`,
|
|
311
|
+
value: key
|
|
312
|
+
})),
|
|
313
|
+
{ name: 'Custom (configure manually)', value: 'custom' }
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
]);
|
|
317
|
+
|
|
318
|
+
config.template = templateAnswer.template;
|
|
319
|
+
|
|
320
|
+
if (config.template === 'custom') {
|
|
321
|
+
const customOptions = await inquirer.prompt([
|
|
322
|
+
{
|
|
323
|
+
type: 'confirm',
|
|
324
|
+
name: 'routing',
|
|
325
|
+
message: 'Enable routing?',
|
|
326
|
+
default: true
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
type: 'list',
|
|
330
|
+
name: 'style',
|
|
331
|
+
message: 'Select stylesheet format:',
|
|
332
|
+
choices: ['css', 'scss', 'sass', 'less']
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
type: 'confirm',
|
|
336
|
+
name: 'strict',
|
|
337
|
+
message: 'Enable strict mode?',
|
|
338
|
+
default: true
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
type: 'confirm',
|
|
342
|
+
name: 'standalone',
|
|
343
|
+
message: 'Use standalone components?',
|
|
344
|
+
default: false
|
|
345
|
+
}
|
|
346
|
+
]);
|
|
347
|
+
|
|
348
|
+
config.options = customOptions;
|
|
349
|
+
} else {
|
|
350
|
+
config.options = PROJECT_TEMPLATES[config.template].options;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Step 9: Library selection (if not from profile)
|
|
355
|
+
if (!config.libraries) {
|
|
356
|
+
const libraryMethod = await askLibrarySearchPreference();
|
|
357
|
+
config.libraries = [];
|
|
358
|
+
|
|
359
|
+
if (libraryMethod === 'interactive') {
|
|
360
|
+
config.libraries = await interactiveLibrarySearch(config.angularVersion);
|
|
361
|
+
} else if (libraryMethod === 'manual') {
|
|
362
|
+
config.libraries = await simpleLibraryInput(config.angularVersion);
|
|
363
|
+
} else if (libraryMethod === 'bundles') {
|
|
364
|
+
const bundleAnswer = await inquirer.prompt([
|
|
365
|
+
{
|
|
366
|
+
type: 'checkbox',
|
|
367
|
+
name: 'bundles',
|
|
368
|
+
message: 'Select library bundles:',
|
|
369
|
+
choices: Object.entries(LIBRARY_BUNDLES).map(([key, bundle]) => ({
|
|
370
|
+
name: `${bundle.name} - ${bundle.description}`,
|
|
371
|
+
value: key
|
|
372
|
+
}))
|
|
373
|
+
}
|
|
374
|
+
]);
|
|
375
|
+
|
|
376
|
+
for (const bundleKey of bundleAnswer.bundles) {
|
|
377
|
+
const bundle = LIBRARY_BUNDLES[bundleKey];
|
|
378
|
+
config.libraries.push(...bundle.packages);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Add template-specific libraries
|
|
383
|
+
if (config.template !== 'custom' && PROJECT_TEMPLATES[config.template].packages) {
|
|
384
|
+
const templateLibs = PROJECT_TEMPLATES[config.template].packages.map(name => ({
|
|
385
|
+
name,
|
|
386
|
+
version: 'latest'
|
|
387
|
+
}));
|
|
388
|
+
config.libraries.push(...templateLibs);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Step 10: Additional features
|
|
393
|
+
const featuresAnswer = await inquirer.prompt([
|
|
394
|
+
{
|
|
395
|
+
type: 'checkbox',
|
|
396
|
+
name: 'features',
|
|
397
|
+
message: 'Select additional features:',
|
|
398
|
+
choices: [
|
|
399
|
+
{ name: 'Git initialization', value: 'git', checked: true },
|
|
400
|
+
{ name: 'Create project structure', value: 'structure', checked: true },
|
|
401
|
+
{ name: 'Generate README.md', value: 'readme', checked: true },
|
|
402
|
+
{ name: 'Generate CHANGELOG.md', value: 'changelog', checked: false },
|
|
403
|
+
{ name: 'ESLint + Prettier setup', value: 'eslint', checked: false },
|
|
404
|
+
{ name: 'Husky pre-commit hooks', value: 'husky', checked: false }
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
]);
|
|
408
|
+
|
|
409
|
+
config.features = featuresAnswer.features;
|
|
410
|
+
|
|
411
|
+
// Step 11: Save profile option
|
|
412
|
+
const saveProfileAnswer = await inquirer.prompt([
|
|
413
|
+
{
|
|
414
|
+
type: 'confirm',
|
|
415
|
+
name: 'save',
|
|
416
|
+
message: 'Save this configuration as a profile?',
|
|
417
|
+
default: false
|
|
418
|
+
}
|
|
419
|
+
]);
|
|
420
|
+
|
|
421
|
+
if (saveProfileAnswer.save) {
|
|
422
|
+
const profileNameAnswer = await inquirer.prompt([
|
|
423
|
+
{
|
|
424
|
+
type: 'input',
|
|
425
|
+
name: 'name',
|
|
426
|
+
message: 'Enter profile name:',
|
|
427
|
+
validate: (value) => value ? true : 'Profile name is required'
|
|
428
|
+
}
|
|
429
|
+
]);
|
|
430
|
+
|
|
431
|
+
await saveProfile(profileNameAnswer.name, config);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Step 12: Confirm and create project
|
|
435
|
+
console.log(chalk.bold.cyan('\n📋 Project Configuration Summary\n'));
|
|
436
|
+
console.log(chalk.gray('━'.repeat(50)));
|
|
437
|
+
console.log(chalk.white('Project Name: ') + chalk.green(config.projectName));
|
|
438
|
+
console.log(chalk.white('Location: ') + chalk.cyan(projectPath));
|
|
439
|
+
console.log(chalk.white('Angular Version: ') + chalk.green(config.angularVersion));
|
|
440
|
+
console.log(chalk.white('Template: ') + chalk.cyan(config.template));
|
|
441
|
+
console.log(chalk.white('Libraries: ') + chalk.cyan(config.libraries.length));
|
|
442
|
+
console.log(chalk.white('Features: ') + chalk.cyan(config.features.join(', ')));
|
|
443
|
+
console.log(chalk.gray('━'.repeat(50)) + '\n');
|
|
444
|
+
|
|
445
|
+
const confirmAnswer = await inquirer.prompt([
|
|
446
|
+
{
|
|
447
|
+
type: 'confirm',
|
|
448
|
+
name: 'confirm',
|
|
449
|
+
message: 'Create project with this configuration?',
|
|
450
|
+
default: true
|
|
451
|
+
}
|
|
452
|
+
]);
|
|
453
|
+
|
|
454
|
+
if (!confirmAnswer.confirm) {
|
|
455
|
+
console.log(chalk.yellow('Project creation cancelled.\n'));
|
|
456
|
+
process.exit(0);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Step 13: Create Angular project
|
|
460
|
+
console.log(chalk.bold.cyan('\n🚀 Creating Angular project...\n'));
|
|
461
|
+
|
|
462
|
+
const createOptions = {
|
|
463
|
+
...config.options,
|
|
464
|
+
skipInstall: true
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const created = await createAngularProject(config.projectName, config.angularVersion, createOptions);
|
|
468
|
+
|
|
469
|
+
if (!created) {
|
|
470
|
+
console.log(chalk.red('Failed to create Angular project.'));
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Step 14: Install libraries
|
|
475
|
+
if (config.libraries.length > 0) {
|
|
476
|
+
console.log(chalk.bold.cyan('\n📦 Installing additional libraries...\n'));
|
|
477
|
+
|
|
478
|
+
// Resolve library versions for compatibility with Angular version
|
|
479
|
+
const resolvedLibraries = resolveLibraryVersions(config.libraries, config.angularVersion);
|
|
480
|
+
|
|
481
|
+
// Show adjusted versions if any
|
|
482
|
+
const adjusted = resolvedLibraries.filter(lib => lib.adjusted);
|
|
483
|
+
if (adjusted.length > 0) {
|
|
484
|
+
console.log(chalk.yellow('⚠️ Adjusted library versions for Angular compatibility:\n'));
|
|
485
|
+
adjusted.forEach(lib => {
|
|
486
|
+
console.log(chalk.gray(` ${lib.name}: ${lib.originalVersion} → ${lib.version}`));
|
|
487
|
+
});
|
|
488
|
+
console.log('');
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const librarySpecs = resolvedLibraries.map(lib =>
|
|
492
|
+
lib.version === 'latest' ? lib.name : `${lib.name}@${lib.version}`
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
await installPackages(librarySpecs, projectPath);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Step 15: Run npm install
|
|
499
|
+
console.log(chalk.bold.cyan('\n📥 Installing dependencies...\n'));
|
|
500
|
+
await runNpmInstall(projectPath);
|
|
501
|
+
|
|
502
|
+
// Step 16: Create project structure
|
|
503
|
+
if (config.features.includes('structure')) {
|
|
504
|
+
console.log(chalk.bold.cyan('\n📁 Creating project structure...\n'));
|
|
505
|
+
await createProjectFolders(projectPath, PROJECT_STRUCTURE.standard.folders);
|
|
506
|
+
await createProjectFiles(projectPath, PROJECT_STRUCTURE.standard.files);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Step 17: Initialize Git
|
|
510
|
+
if (config.features.includes('git')) {
|
|
511
|
+
console.log(chalk.bold.cyan('\n🔧 Initializing Git repository...\n'));
|
|
512
|
+
await initGitRepo(projectPath);
|
|
513
|
+
await createGitignore(projectPath, GIT_CONFIG.gitignore);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Step 18: Generate documentation
|
|
517
|
+
if (config.features.includes('readme')) {
|
|
518
|
+
console.log(chalk.bold.cyan('\n📝 Generating README.md...\n'));
|
|
519
|
+
const readmeContent = DOC_TEMPLATES.readme(config.projectName, 'An Angular application created with Angular Project Automator');
|
|
520
|
+
await createReadme(projectPath, readmeContent);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (config.features.includes('changelog')) {
|
|
524
|
+
await createChangelog(projectPath, DOC_TEMPLATES.changelog);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Step 19: Setup ESLint
|
|
528
|
+
if (config.features.includes('eslint')) {
|
|
529
|
+
console.log(chalk.bold.cyan('\n🔧 Setting up ESLint + Prettier...\n'));
|
|
530
|
+
const eslintPackages = CONFIG_PRESETS.eslint.packages.map(p => p);
|
|
531
|
+
await installPackages(eslintPackages, projectPath, true);
|
|
532
|
+
await createProjectFiles(projectPath, CONFIG_PRESETS.eslint.files);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Step 20: Setup Husky
|
|
536
|
+
if (config.features.includes('husky')) {
|
|
537
|
+
console.log(chalk.bold.cyan('\n🐶 Setting up Husky...\n'));
|
|
538
|
+
const huskyPackages = CONFIG_PRESETS.husky.devPackages.map(p => p);
|
|
539
|
+
await installPackages(huskyPackages, projectPath, true);
|
|
540
|
+
await updatePackageJsonScripts(projectPath, CONFIG_PRESETS.husky.scripts);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Step 21: Create initial commit
|
|
544
|
+
if (config.features.includes('git')) {
|
|
545
|
+
console.log(chalk.bold.cyan('\n📝 Creating initial commit...\n'));
|
|
546
|
+
await createInitialCommit(projectPath, GIT_CONFIG.initialCommitMessage);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Step 22: Display success message
|
|
550
|
+
console.log(chalk.bold.green('\n✅ Project created successfully! 🎉\n'));
|
|
551
|
+
console.log(chalk.bold.cyan('📊 Next Steps:\n'));
|
|
552
|
+
console.log(chalk.gray('━'.repeat(50)));
|
|
553
|
+
console.log(chalk.white('1. ') + chalk.cyan(`cd ${config.projectName}`));
|
|
554
|
+
console.log(chalk.white('2. ') + chalk.cyan('ng serve'));
|
|
555
|
+
console.log(chalk.white('3. ') + chalk.cyan('Open http://localhost:4200 in your browser'));
|
|
556
|
+
console.log(chalk.gray('━'.repeat(50)));
|
|
557
|
+
|
|
558
|
+
console.log(chalk.bold.cyan('\n💡 Useful Commands:\n'));
|
|
559
|
+
console.log(chalk.gray(' ng generate component <name> ') + chalk.white('Create a component'));
|
|
560
|
+
console.log(chalk.gray(' ng generate service <name> ') + chalk.white('Create a service'));
|
|
561
|
+
console.log(chalk.gray(' ng build ') + chalk.white('Build for production'));
|
|
562
|
+
console.log(chalk.gray(' ng test ') + chalk.white('Run unit tests'));
|
|
563
|
+
console.log(chalk.gray(' ng help ') + chalk.white('Get more help\n'));
|
|
564
|
+
|
|
565
|
+
console.log(chalk.bold.green('Happy coding! 🚀\n'));
|
|
566
|
+
|
|
567
|
+
} catch (err) {
|
|
568
|
+
console.error(chalk.red('\n❌ Error:'), err.message);
|
|
569
|
+
if (err.stack) {
|
|
570
|
+
console.error(chalk.gray(err.stack));
|
|
571
|
+
}
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
}
|