initkit 1.1.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/LICENSE +21 -0
- package/README.md +844 -0
- package/bin/index.js +8 -0
- package/package.json +79 -0
- package/src/cli.js +264 -0
- package/src/commands/create.js +264 -0
- package/src/index.js +9 -0
- package/src/prompts/questions.js +358 -0
- package/src/templates/express.js +915 -0
- package/src/templates/fullstack.js +1236 -0
- package/src/templates/nextjs.js +620 -0
- package/src/templates/react.js +586 -0
- package/src/templates/vue.js +545 -0
- package/src/utils/errorHandler.js +275 -0
- package/src/utils/git.js +69 -0
- package/src/utils/packageManager.js +90 -0
- package/src/utils/templateGenerator.js +365 -0
- package/src/utils/validation.js +186 -0
- package/src/utils/versionFetcher.js +128 -0
package/bin/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "initkit",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A modern CLI tool for scaffolding production-ready web projects with live npm version fetching, multiple frameworks, and best practices built-in",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"initkit": "./bin/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node bin/index.js",
|
|
12
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
13
|
+
"test:watch": "npm test -- --watch",
|
|
14
|
+
"test:coverage": "npm test -- --coverage",
|
|
15
|
+
"test:unit": "npm test -- __tests__/unit",
|
|
16
|
+
"test:integration": "npm test -- __tests__/integration",
|
|
17
|
+
"lint": "eslint src/**/*.js",
|
|
18
|
+
"format": "prettier --write \"src/**/*.js\"",
|
|
19
|
+
"prepublishOnly": "npm test && npm run lint"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"cli",
|
|
23
|
+
"scaffold",
|
|
24
|
+
"generator",
|
|
25
|
+
"project-initializer",
|
|
26
|
+
"boilerplate",
|
|
27
|
+
"template",
|
|
28
|
+
"starter",
|
|
29
|
+
"web-development",
|
|
30
|
+
"react",
|
|
31
|
+
"nextjs",
|
|
32
|
+
"vue",
|
|
33
|
+
"express",
|
|
34
|
+
"typescript",
|
|
35
|
+
"fullstack",
|
|
36
|
+
"monorepo",
|
|
37
|
+
"vite",
|
|
38
|
+
"tailwind",
|
|
39
|
+
"redux-toolkit",
|
|
40
|
+
"prisma",
|
|
41
|
+
"docker",
|
|
42
|
+
"turborepo"
|
|
43
|
+
],
|
|
44
|
+
"author": "Shirish Shrestha <shirishshrestha07@gmail.com>",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/shirishshrestha/initkit.git"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/shirishshrestha/initkit/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://github.com/shirishshrestha/initkit#readme",
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=14.0.0"
|
|
56
|
+
},
|
|
57
|
+
"files": [
|
|
58
|
+
"bin/",
|
|
59
|
+
"src/",
|
|
60
|
+
"templates/",
|
|
61
|
+
"README.md",
|
|
62
|
+
"LICENSE"
|
|
63
|
+
],
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"chalk": "^5.3.0",
|
|
66
|
+
"commander": "^12.0.0",
|
|
67
|
+
"inquirer": "^9.2.15",
|
|
68
|
+
"ora": "^8.0.1",
|
|
69
|
+
"fs-extra": "^11.2.0",
|
|
70
|
+
"ejs": "^3.1.9",
|
|
71
|
+
"validate-npm-package-name": "^5.0.0"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"eslint": "^8.56.0",
|
|
75
|
+
"prettier": "^3.2.4",
|
|
76
|
+
"jest": "^29.7.0",
|
|
77
|
+
"@types/node": "^20.11.5"
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { program } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { createProject } from './commands/create.js';
|
|
5
|
+
import { getQuestions } from './prompts/questions.js';
|
|
6
|
+
import { createRequire } from 'module';
|
|
7
|
+
import {
|
|
8
|
+
displayError,
|
|
9
|
+
CLIError,
|
|
10
|
+
ERROR_CODES,
|
|
11
|
+
setupGracefulShutdown,
|
|
12
|
+
} from './utils/errorHandler.js';
|
|
13
|
+
import { validateProjectName, checkDirectoryExists } from './utils/validation.js';
|
|
14
|
+
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const packageJson = require('../package.json');
|
|
17
|
+
|
|
18
|
+
// Display banner
|
|
19
|
+
function displayBanner() {
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(chalk.cyan('╔════════════════════════════════════════════════════════════╗'));
|
|
22
|
+
console.log(chalk.cyan('║') + chalk.cyan.bold(' ') + chalk.cyan('║'));
|
|
23
|
+
console.log(chalk.cyan('║') + chalk.cyan.bold(' Welcome to InitKit CLI! ') + chalk.cyan('║'));
|
|
24
|
+
console.log(chalk.cyan('║') + chalk.cyan.bold(' ') + chalk.cyan('║'));
|
|
25
|
+
console.log(chalk.cyan('║') + chalk.white(' Scaffold modern web projects with best ') + chalk.cyan('║'));
|
|
26
|
+
console.log(chalk.cyan('║') + chalk.white(' practices and lightning-fast speed ⚡ ') + chalk.cyan('║'));
|
|
27
|
+
console.log(chalk.cyan('║') + chalk.cyan.bold(' ') + chalk.cyan('║'));
|
|
28
|
+
console.log(chalk.cyan('╚════════════════════════════════════════════════════════════╝'));
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log(chalk.gray(` Version ${packageJson.version} | Made with ❤️ by developers\n`));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Set up the CLI program
|
|
34
|
+
|
|
35
|
+
program
|
|
36
|
+
.name('initkit')
|
|
37
|
+
.description(packageJson.description)
|
|
38
|
+
.usage('[command] [options]')
|
|
39
|
+
.version(packageJson.version, '-v, --version', 'Output the current version')
|
|
40
|
+
.addHelpText('after', `
|
|
41
|
+
Examples:
|
|
42
|
+
$ initkit # Interactive mode with step-by-step prompts
|
|
43
|
+
$ initkit my-app # Create project with interactive prompts
|
|
44
|
+
$ initkit my-app --yes # Use defaults, skip all prompts
|
|
45
|
+
$ initkit my-app --ts --no-git # TypeScript without Git initialization
|
|
46
|
+
|
|
47
|
+
Documentation:
|
|
48
|
+
Quick Start: https://github.com/shirishshrestha/initkit/blob/main/docs/QUICK_START.md
|
|
49
|
+
User Guide: https://github.com/shirishshrestha/initkit/blob/main/docs/user-guide.md
|
|
50
|
+
GitHub: https://github.com/shirishshrestha/initkit
|
|
51
|
+
|
|
52
|
+
Need help? Report issues at: https://github.com/shirishshrestha/initkit/issues
|
|
53
|
+
`);
|
|
54
|
+
|
|
55
|
+
// Main create command
|
|
56
|
+
program
|
|
57
|
+
.command('create [project-name]', { isDefault: true })
|
|
58
|
+
.description('Create a new project with interactive prompts')
|
|
59
|
+
.option('-t, --template <template>', 'Specify template (react, vue, express, etc.)')
|
|
60
|
+
.option('-y, --yes', 'Skip prompts and use sensible defaults')
|
|
61
|
+
.option('--ts, --typescript', 'Use TypeScript (recommended)')
|
|
62
|
+
.option('--js, --javascript', 'Use JavaScript instead of TypeScript')
|
|
63
|
+
.option('--no-git', 'Skip Git repository initialization')
|
|
64
|
+
.option('--no-install', 'Skip automatic dependency installation')
|
|
65
|
+
.option('-p, --package-manager <manager>', 'Package manager (npm, yarn, pnpm)', 'npm')
|
|
66
|
+
.option('--verbose', 'Show detailed output and logs')
|
|
67
|
+
.addHelpText('after', `
|
|
68
|
+
Examples:
|
|
69
|
+
$ initkit create my-react-app
|
|
70
|
+
$ initkit create api-server --template express --typescript
|
|
71
|
+
$ initkit create quick-app --yes --package-manager yarn
|
|
72
|
+
|
|
73
|
+
The create command guides you through an interactive setup with 13 questions:
|
|
74
|
+
1. Project name validation
|
|
75
|
+
2. Project type selection (Frontend/Backend/Full Stack/Library)
|
|
76
|
+
3. Framework selection (React, Vue, Express, etc.)
|
|
77
|
+
4. Language preference (TypeScript/JavaScript)
|
|
78
|
+
5. Folder structure (Feature-based, Type-based, etc.)
|
|
79
|
+
6. Styling solution (Tailwind, CSS Modules, etc.)
|
|
80
|
+
7. Additional tools (Docker, CI/CD, Testing)
|
|
81
|
+
8. Package manager choice
|
|
82
|
+
9. Git initialization
|
|
83
|
+
`)
|
|
84
|
+
.action(async (projectName, options) => {
|
|
85
|
+
try {
|
|
86
|
+
displayBanner();
|
|
87
|
+
|
|
88
|
+
let answers;
|
|
89
|
+
let projectPath;
|
|
90
|
+
|
|
91
|
+
// Validate project name if provided
|
|
92
|
+
if (projectName) {
|
|
93
|
+
const validation = validateProjectName(projectName);
|
|
94
|
+
if (!validation.valid) {
|
|
95
|
+
const suggestion = require('../utils/validation.js').suggestProjectName(projectName);
|
|
96
|
+
throw new CLIError(
|
|
97
|
+
`"${projectName}" is not a valid project name`,
|
|
98
|
+
ERROR_CODES.VALIDATION_ERROR,
|
|
99
|
+
{ suggestion: suggestion, issue: validation.errors[0] }
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Check if directory exists
|
|
104
|
+
const dirCheck = checkDirectoryExists(projectName);
|
|
105
|
+
if (dirCheck.exists) {
|
|
106
|
+
throw new CLIError(
|
|
107
|
+
`A folder named "${projectName}" already exists here`,
|
|
108
|
+
ERROR_CODES.DIRECTORY_EXISTS,
|
|
109
|
+
{ path: dirCheck.path, projectName }
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
projectPath = dirCheck.path;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (options.yes) {
|
|
117
|
+
// Use default configuration
|
|
118
|
+
answers = {
|
|
119
|
+
projectName: projectName || 'my-project',
|
|
120
|
+
projectType: 'fullstack',
|
|
121
|
+
frontend: 'react',
|
|
122
|
+
backend: 'express',
|
|
123
|
+
language: options.javascript ? 'javascript' : 'typescript',
|
|
124
|
+
folderStructure: 'feature-based',
|
|
125
|
+
typescriptStrict: 'strict',
|
|
126
|
+
useGit: options.git !== false,
|
|
127
|
+
installDependencies: options.install !== false,
|
|
128
|
+
packageManager: options.packageManager || 'npm',
|
|
129
|
+
features: ['eslint', 'prettier', 'dotenv'],
|
|
130
|
+
additionalLibraries: [],
|
|
131
|
+
};
|
|
132
|
+
} else {
|
|
133
|
+
// Interactive prompts
|
|
134
|
+
console.log(chalk.cyan('Let\'s set up your project!\n'));
|
|
135
|
+
const questions = getQuestions(projectName);
|
|
136
|
+
answers = await inquirer.prompt(questions);
|
|
137
|
+
|
|
138
|
+
// Set additional options from CLI flags
|
|
139
|
+
if (options.javascript) {
|
|
140
|
+
answers.language = 'javascript';
|
|
141
|
+
}
|
|
142
|
+
answers.useGit = options.git !== false;
|
|
143
|
+
answers.installDependencies = options.install !== false;
|
|
144
|
+
answers.packageManager = options.packageManager || answers.packageManager;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Derive projectPath if not set
|
|
148
|
+
if (!projectPath) {
|
|
149
|
+
projectPath = checkDirectoryExists(answers.projectName).path;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Setup graceful shutdown handler
|
|
153
|
+
setupGracefulShutdown(projectPath);
|
|
154
|
+
|
|
155
|
+
// Create the project
|
|
156
|
+
console.log(chalk.cyan('\nCreating your project...\n'));
|
|
157
|
+
await createProject(answers, {
|
|
158
|
+
verbose: options.verbose,
|
|
159
|
+
projectPath,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Success message is now part of the comprehensive summary in create.js
|
|
163
|
+
|
|
164
|
+
} catch (error) {
|
|
165
|
+
displayError(error, { projectName });
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Info command
|
|
171
|
+
program
|
|
172
|
+
.command('info')
|
|
173
|
+
.description('Display detailed information about InitKit CLI')
|
|
174
|
+
.action(() => {
|
|
175
|
+
console.log(chalk.cyan.bold('\n╔════════════════════════════════════════════════╗'));
|
|
176
|
+
console.log(chalk.cyan.bold('║ InitKit CLI Information ║'));
|
|
177
|
+
console.log(chalk.cyan.bold('╚════════════════════════════════════════════════╝\n'));
|
|
178
|
+
|
|
179
|
+
console.log(chalk.white.bold('Version: ') + chalk.green(packageJson.version));
|
|
180
|
+
console.log(chalk.white.bold('Description: ') + chalk.gray(packageJson.description));
|
|
181
|
+
console.log(chalk.white.bold('Author: ') + chalk.gray(packageJson.author));
|
|
182
|
+
console.log(chalk.white.bold('License: ') + chalk.gray(packageJson.license));
|
|
183
|
+
console.log(chalk.white.bold('Repository: ') + chalk.blue(packageJson.repository?.url || 'N/A'));
|
|
184
|
+
|
|
185
|
+
console.log(chalk.yellow.bold('\nSupported Frameworks:'));
|
|
186
|
+
console.log(chalk.gray(' Frontend: ') + 'React, Vue, Next.js, Angular, Svelte, Nuxt');
|
|
187
|
+
console.log(chalk.gray(' Backend: ') + 'Express, NestJS, Fastify, Koa, Hapi');
|
|
188
|
+
console.log(chalk.gray(' Database: ') + 'PostgreSQL, MongoDB, MySQL, SQLite');
|
|
189
|
+
|
|
190
|
+
console.log(chalk.yellow.bold('\nFeatures:'));
|
|
191
|
+
console.log(chalk.gray(' ✓ Interactive project scaffolding'));
|
|
192
|
+
console.log(chalk.gray(' ✓ TypeScript & JavaScript support'));
|
|
193
|
+
console.log(chalk.gray(' ✓ Full-stack monorepo with Turborepo'));
|
|
194
|
+
console.log(chalk.gray(' ✓ Docker & Docker Compose'));
|
|
195
|
+
console.log(chalk.gray(' ✓ CI/CD with GitHub Actions'));
|
|
196
|
+
console.log(chalk.gray(' ✓ ESLint, Prettier, Husky'));
|
|
197
|
+
console.log(chalk.gray(' ✓ Automatic rollback on errors'));
|
|
198
|
+
|
|
199
|
+
console.log(chalk.cyan('\n💡 Get started: ') + chalk.white('initkit --help\n'));
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// List command - show available templates
|
|
203
|
+
program
|
|
204
|
+
.command('list')
|
|
205
|
+
.description('List all available project templates, frameworks, and tools')
|
|
206
|
+
.action(() => {
|
|
207
|
+
console.log(chalk.cyan.bold('\n╔════════════════════════════════════════════════╗'));
|
|
208
|
+
console.log(chalk.cyan.bold('║ Available Templates & Tools ║'));
|
|
209
|
+
console.log(chalk.cyan.bold('╚════════════════════════════════════════════════╝\n'));
|
|
210
|
+
|
|
211
|
+
console.log(chalk.yellow.bold('🎨 Frontend Frameworks:'));
|
|
212
|
+
console.log(chalk.gray(' • React ') + chalk.dim('- Popular library for building UIs'));
|
|
213
|
+
console.log(chalk.gray(' • Vue.js ') + chalk.dim('- Progressive JavaScript framework'));
|
|
214
|
+
console.log(chalk.gray(' • Next.js ') + chalk.dim('- React framework with SSR & SSG'));
|
|
215
|
+
console.log(chalk.gray(' • Angular ') + chalk.dim('- Platform for building applications'));
|
|
216
|
+
console.log(chalk.gray(' • Svelte ') + chalk.dim('- Compile-time framework'));
|
|
217
|
+
console.log(chalk.gray(' • Nuxt.js ') + chalk.dim('- Vue.js framework with SSR'));
|
|
218
|
+
|
|
219
|
+
console.log(chalk.yellow.bold('\n⚙️ Backend Frameworks:'));
|
|
220
|
+
console.log(chalk.gray(' • Express.js ') + chalk.dim('- Fast, minimalist web framework'));
|
|
221
|
+
console.log(chalk.gray(' • NestJS ') + chalk.dim('- Progressive Node.js framework'));
|
|
222
|
+
console.log(chalk.gray(' • Fastify ') + chalk.dim('- Fast and low overhead'));
|
|
223
|
+
console.log(chalk.gray(' • Koa ') + chalk.dim('- Next generation web framework'));
|
|
224
|
+
console.log(chalk.gray(' • Hapi ') + chalk.dim('- Rich framework for building applications'));
|
|
225
|
+
|
|
226
|
+
console.log(chalk.yellow.bold('\n💾 Databases:'));
|
|
227
|
+
console.log(chalk.gray(' • PostgreSQL ') + chalk.dim('- Advanced relational database'));
|
|
228
|
+
console.log(chalk.gray(' • MongoDB ') + chalk.dim('- NoSQL document database'));
|
|
229
|
+
console.log(chalk.gray(' • MySQL ') + chalk.dim('- Popular relational database'));
|
|
230
|
+
console.log(chalk.gray(' • SQLite ') + chalk.dim('- Lightweight embedded database'));
|
|
231
|
+
|
|
232
|
+
console.log(chalk.yellow.bold('\n🎨 Styling Solutions:'));
|
|
233
|
+
console.log(chalk.gray(' • Tailwind CSS ') + chalk.dim('- Utility-first CSS framework'));
|
|
234
|
+
console.log(chalk.gray(' • CSS Modules ') + chalk.dim('- Locally scoped CSS'));
|
|
235
|
+
console.log(chalk.gray(' • Styled Comp. ') + chalk.dim('- CSS-in-JS solution'));
|
|
236
|
+
console.log(chalk.gray(' • Sass/SCSS ') + chalk.dim('- CSS preprocessor'));
|
|
237
|
+
console.log(chalk.gray(' • Emotion ') + chalk.dim('- Performant CSS-in-JS'));
|
|
238
|
+
|
|
239
|
+
console.log(chalk.yellow.bold('\n🛠️ Development Tools:'));
|
|
240
|
+
console.log(chalk.gray(' • Docker ') + chalk.dim('- Containerization'));
|
|
241
|
+
console.log(chalk.gray(' • GitHub Actions ') + chalk.dim('- CI/CD automation'));
|
|
242
|
+
console.log(chalk.gray(' • ESLint ') + chalk.dim('- Code linting'));
|
|
243
|
+
console.log(chalk.gray(' • Prettier ') + chalk.dim('- Code formatting'));
|
|
244
|
+
console.log(chalk.gray(' • Jest/Vitest ') + chalk.dim('- Testing frameworks'));
|
|
245
|
+
console.log(chalk.gray(' • Turborepo ') + chalk.dim('- Monorepo build system'));
|
|
246
|
+
|
|
247
|
+
console.log(chalk.cyan('\n💡 Create a project: ') + chalk.white('initkit [project-name]\n'));
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Handle unknown commands
|
|
251
|
+
program.on('command:*', () => {
|
|
252
|
+
console.error(chalk.red('\nInvalid command: %s'), program.args.join(' '));
|
|
253
|
+
console.log(chalk.yellow('See --help for a list of available commands.\n'));
|
|
254
|
+
process.exit(1);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Show help if no arguments provided
|
|
258
|
+
if (!process.argv.slice(2).length) {
|
|
259
|
+
displayBanner();
|
|
260
|
+
program.outputHelp();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Parse command-line arguments
|
|
264
|
+
program.parse();
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { generateTemplate } from '../utils/templateGenerator.js';
|
|
6
|
+
import { installDependencies } from '../utils/packageManager.js';
|
|
7
|
+
import { initGit } from '../utils/git.js';
|
|
8
|
+
import {
|
|
9
|
+
CLIError,
|
|
10
|
+
ERROR_CODES,
|
|
11
|
+
withErrorHandling,
|
|
12
|
+
rollbackProject,
|
|
13
|
+
safeFileOperation,
|
|
14
|
+
} from '../utils/errorHandler.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a new project based on user configuration
|
|
18
|
+
*
|
|
19
|
+
* This is the main orchestration function that:
|
|
20
|
+
* 1. Creates the project directory
|
|
21
|
+
* 2. Generates template files
|
|
22
|
+
* 3. Installs dependencies
|
|
23
|
+
* 4. Initializes Git repository
|
|
24
|
+
* 5. Handles errors with automatic rollback
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} answers - User's configuration from interactive prompts
|
|
27
|
+
* @param {string} answers.projectName - Name of the project (used for directory)
|
|
28
|
+
* @param {string} answers.projectType - Type of project ('frontend'|'backend'|'fullstack'|'library')
|
|
29
|
+
* @param {string} [answers.frontend] - Frontend framework choice
|
|
30
|
+
* @param {string} [answers.backend] - Backend framework choice
|
|
31
|
+
* @param {string} answers.language - Programming language ('typescript'|'javascript')
|
|
32
|
+
* @param {string} answers.packageManager - Package manager ('npm'|'yarn'|'pnpm')
|
|
33
|
+
* @param {boolean} [answers.gitInit] - Whether to initialize Git repository
|
|
34
|
+
*
|
|
35
|
+
* @param {Object} [options={}] - Additional command-line options
|
|
36
|
+
* @param {boolean} [options.verbose=false] - Show detailed output during creation
|
|
37
|
+
* @param {string} [options.projectPath] - Custom path for project (overrides answers.projectName)
|
|
38
|
+
*
|
|
39
|
+
* @returns {Promise<void>}
|
|
40
|
+
* @throws {CLIError} If project creation fails at any step (automatic rollback triggered)
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // Basic usage
|
|
44
|
+
* await createProject({
|
|
45
|
+
* projectName: 'my-app',
|
|
46
|
+
* projectType: 'frontend',
|
|
47
|
+
* frontend: 'react',
|
|
48
|
+
* language: 'typescript',
|
|
49
|
+
* packageManager: 'npm',
|
|
50
|
+
* gitInit: true
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // With verbose output
|
|
55
|
+
* await createProject(answers, { verbose: true });
|
|
56
|
+
*/
|
|
57
|
+
async function createProject(answers, options = {}) {
|
|
58
|
+
const { verbose = false, projectPath: customProjectPath } = options;
|
|
59
|
+
const projectPath = customProjectPath || path.join(process.cwd(), answers.projectName);
|
|
60
|
+
let spinner;
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// Step 1: Check if directory already exists
|
|
64
|
+
if (await fs.pathExists(projectPath)) {
|
|
65
|
+
throw new CLIError(
|
|
66
|
+
`Directory "${answers.projectName}" already exists!`,
|
|
67
|
+
ERROR_CODES.DIRECTORY_EXISTS,
|
|
68
|
+
{ path: projectPath }
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Step 2: Create project directory
|
|
73
|
+
spinner = ora({
|
|
74
|
+
text: 'Creating project structure...',
|
|
75
|
+
color: 'cyan',
|
|
76
|
+
}).start();
|
|
77
|
+
|
|
78
|
+
await safeFileOperation(
|
|
79
|
+
() => fs.ensureDir(projectPath),
|
|
80
|
+
'Creating project directory'
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (verbose) {
|
|
84
|
+
spinner.info(chalk.gray(`Created directory: ${projectPath}`));
|
|
85
|
+
spinner.start('Generating project files...');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Step 3: Generate project files from templates
|
|
89
|
+
await withErrorHandling(
|
|
90
|
+
() => generateTemplate(projectPath, answers),
|
|
91
|
+
{
|
|
92
|
+
projectPath,
|
|
93
|
+
rollback: true,
|
|
94
|
+
errorCode: ERROR_CODES.CREATION_FAILED,
|
|
95
|
+
context: { step: 'template generation' },
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
spinner.succeed(chalk.green('Project structure created'));
|
|
100
|
+
|
|
101
|
+
// Step 4: Initialize Git if requested
|
|
102
|
+
if (answers.useGit) {
|
|
103
|
+
const gitSpinner = ora('Initializing Git repository...').start();
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
await initGit(projectPath);
|
|
107
|
+
gitSpinner.succeed(chalk.green('Git repository initialized'));
|
|
108
|
+
} catch (error) {
|
|
109
|
+
gitSpinner.warn(chalk.yellow('Git initialization skipped'));
|
|
110
|
+
|
|
111
|
+
if (verbose) {
|
|
112
|
+
console.log(chalk.gray(` Reason: ${error.message}`));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Step 5: Install dependencies
|
|
118
|
+
if (answers.installDependencies !== false) {
|
|
119
|
+
try {
|
|
120
|
+
await installDependencies(projectPath, answers.packageManager, {
|
|
121
|
+
verbose,
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
// Don't fail the entire process if install fails
|
|
125
|
+
console.log(chalk.yellow('\nDependency installation failed'));
|
|
126
|
+
console.log(chalk.gray(' You can install them manually later\n'));
|
|
127
|
+
|
|
128
|
+
if (verbose) {
|
|
129
|
+
console.log(chalk.gray(` Error: ${error.message}`));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
console.log(chalk.gray('\n Skipping dependency installation (--no-install)'));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Step 6: Display comprehensive success summary
|
|
137
|
+
displaySuccessSummary(answers, projectPath, verbose);
|
|
138
|
+
|
|
139
|
+
} catch (error) {
|
|
140
|
+
// Stop any running spinners
|
|
141
|
+
if (spinner && spinner.isSpinning) {
|
|
142
|
+
spinner.fail(chalk.red('Project creation failed'));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// If it's already a CLIError, just re-throw it
|
|
146
|
+
if (error instanceof CLIError) {
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Wrap unexpected errors
|
|
151
|
+
throw new CLIError(
|
|
152
|
+
`Failed to create project: ${error.message}`,
|
|
153
|
+
ERROR_CODES.CREATION_FAILED,
|
|
154
|
+
{ originalError: error.name, path: projectPath }
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Display comprehensive success summary after project creation
|
|
161
|
+
* @param {Object} answers - Project configuration
|
|
162
|
+
* @param {string} projectPath - Path to the project
|
|
163
|
+
* @param {boolean} verbose - Show detailed information
|
|
164
|
+
*/
|
|
165
|
+
function displaySuccessSummary(answers, projectPath, verbose = false) {
|
|
166
|
+
console.log('');
|
|
167
|
+
console.log(chalk.green('╔════════════════════════════════════════════════════════════╗'));
|
|
168
|
+
console.log(chalk.green('║') + chalk.green.bold(' ✨ Project Created Successfully! ✨ ') + chalk.green('║'));
|
|
169
|
+
console.log(chalk.green('╚════════════════════════════════════════════════════════════╝'));
|
|
170
|
+
console.log('');
|
|
171
|
+
|
|
172
|
+
// Project info section
|
|
173
|
+
console.log(chalk.cyan.bold(' 📦 Project Information'));
|
|
174
|
+
console.log(chalk.white(` ${chalk.gray('Name:')} ${chalk.bold(answers.projectName)}`));
|
|
175
|
+
console.log(chalk.white(` ${chalk.gray('Type:')} ${answers.projectType}`));
|
|
176
|
+
console.log(chalk.white(` ${chalk.gray('Language:')} ${answers.language || 'JavaScript'}`));
|
|
177
|
+
|
|
178
|
+
if (answers.frontend) {
|
|
179
|
+
console.log(chalk.white(` ${chalk.gray('Frontend:')} ${answers.frontend}`));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (answers.backend) {
|
|
183
|
+
console.log(chalk.white(` ${chalk.gray('Backend:')} ${answers.backend}`));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (answers.fullstackType) {
|
|
187
|
+
console.log(chalk.white(` ${chalk.gray('Architecture:')} ${answers.fullstackType}`));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (answers.database && answers.database !== 'none') {
|
|
191
|
+
console.log(chalk.white(` ${chalk.gray('Database:')} ${answers.database}`));
|
|
192
|
+
}
|
|
193
|
+
console.log('');
|
|
194
|
+
|
|
195
|
+
// Location section
|
|
196
|
+
console.log(chalk.cyan.bold(' 📁 Project Location'));
|
|
197
|
+
console.log(chalk.white(` ${projectPath}`));
|
|
198
|
+
console.log('');
|
|
199
|
+
|
|
200
|
+
// Features section
|
|
201
|
+
if (answers.features && answers.features.length > 0) {
|
|
202
|
+
console.log(chalk.cyan.bold(' ⚙️ Configured Features'));
|
|
203
|
+
answers.features.forEach(feature => {
|
|
204
|
+
console.log(chalk.white(` ${chalk.green('✓')} ${feature}`));
|
|
205
|
+
});
|
|
206
|
+
console.log('');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Additional libraries
|
|
210
|
+
if (answers.additionalLibraries && answers.additionalLibraries.length > 0) {
|
|
211
|
+
console.log(chalk.cyan.bold(' 📚 Additional Libraries'));
|
|
212
|
+
answers.additionalLibraries.slice(0, 5).forEach(lib => {
|
|
213
|
+
console.log(chalk.white(` ${chalk.green('✓')} ${lib}`));
|
|
214
|
+
});
|
|
215
|
+
if (answers.additionalLibraries.length > 5) {
|
|
216
|
+
console.log(chalk.gray(` ... and ${answers.additionalLibraries.length - 5} more`));
|
|
217
|
+
}
|
|
218
|
+
console.log('');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Package manager info
|
|
222
|
+
const packagesInstalled = answers.installDependencies !== false;
|
|
223
|
+
if (packagesInstalled) {
|
|
224
|
+
console.log(chalk.cyan.bold(' 📦 Dependencies'));
|
|
225
|
+
console.log(chalk.white(` ${chalk.green('✓')} Installed with ${answers.packageManager}`));
|
|
226
|
+
console.log('');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Next steps
|
|
230
|
+
console.log(chalk.cyan.bold(' 🚀 Next Steps'));
|
|
231
|
+
console.log('');
|
|
232
|
+
console.log(chalk.white(` ${chalk.yellow('1.')} Navigate to your project:`));
|
|
233
|
+
console.log(chalk.gray(` cd ${answers.projectName}`));
|
|
234
|
+
console.log('');
|
|
235
|
+
|
|
236
|
+
if (!packagesInstalled) {
|
|
237
|
+
console.log(chalk.white(` ${chalk.yellow('2.')} Install dependencies:`));
|
|
238
|
+
console.log(chalk.gray(` ${answers.packageManager} install`));
|
|
239
|
+
console.log('');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const stepNum = packagesInstalled ? 2 : 3;
|
|
243
|
+
console.log(chalk.white(` ${chalk.yellow(stepNum + '.')} Start development server:`));
|
|
244
|
+
console.log(chalk.gray(` ${answers.packageManager} ${answers.packageManager === 'npm' ? 'run ' : ''}dev`));
|
|
245
|
+
console.log('');
|
|
246
|
+
|
|
247
|
+
console.log(chalk.white(` ${chalk.yellow((stepNum + 1) + '.')} Read the README for more info:`));
|
|
248
|
+
console.log(chalk.gray(` cat README.md`));
|
|
249
|
+
console.log('');
|
|
250
|
+
|
|
251
|
+
// Documentation link
|
|
252
|
+
console.log(chalk.cyan.bold(' 📚 Documentation'));
|
|
253
|
+
console.log(chalk.white(` Check out the README.md in your project folder`));
|
|
254
|
+
console.log(chalk.white(` for setup instructions and best practices.`));
|
|
255
|
+
console.log('');
|
|
256
|
+
|
|
257
|
+
// Footer
|
|
258
|
+
console.log(chalk.green(' ─────────────────────────────────────────────────────────────'));
|
|
259
|
+
console.log(chalk.green.bold(' 🎉 Happy coding! Your project is ready! 🎉'));
|
|
260
|
+
console.log(chalk.green(' ─────────────────────────────────────────────────────────────'));
|
|
261
|
+
console.log('');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export { createProject };
|
package/src/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for programmatic usage
|
|
3
|
+
* This allows the package to be used as a library, not just a CLI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createProject } from './commands/create.js';
|
|
7
|
+
import { getQuestions } from './prompts/questions.js';
|
|
8
|
+
|
|
9
|
+
export { createProject, getQuestions };
|