build-app-with 2.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.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/bin/cli.js +18 -0
  4. package/index.js +3 -0
  5. package/package.json +80 -0
  6. package/src/__tests__/core/error-handler.test.js +99 -0
  7. package/src/__tests__/core/logger.test.js +93 -0
  8. package/src/__tests__/e2e/cli-integration.test.js +220 -0
  9. package/src/__tests__/e2e/framework-generation.test.js +249 -0
  10. package/src/__tests__/setup.js +70 -0
  11. package/src/config/package-mappings.js +110 -0
  12. package/src/constants/index.js +42 -0
  13. package/src/core/error-handler.js +89 -0
  14. package/src/core/logger.js +89 -0
  15. package/src/core/package-manager.js +114 -0
  16. package/src/create-app.js +90 -0
  17. package/src/generators/express/index.js +52 -0
  18. package/src/generators/express/project-generator.js +367 -0
  19. package/src/generators/express/prompts.js +74 -0
  20. package/src/generators/express/simple-generator.js +275 -0
  21. package/src/generators/express/templates/app.js +73 -0
  22. package/src/generators/express/templates/config/database.js +122 -0
  23. package/src/generators/express/templates/config.js +37 -0
  24. package/src/generators/express/templates/controllers.js +49 -0
  25. package/src/generators/express/templates/docker.js +72 -0
  26. package/src/generators/express/templates/middleware/errorHandler.js +49 -0
  27. package/src/generators/express/templates/middleware.js +59 -0
  28. package/src/generators/express/templates/models.js +77 -0
  29. package/src/generators/express/templates/package-json.js +55 -0
  30. package/src/generators/express/templates/readme.js +310 -0
  31. package/src/generators/express/templates/routes.js +36 -0
  32. package/src/generators/express/templates/server.js +59 -0
  33. package/src/generators/express/templates/services.js +55 -0
  34. package/src/generators/express/templates/tests.js +46 -0
  35. package/src/generators/express/templates/utils/logger.js +54 -0
  36. package/src/generators/fastify/index.js +46 -0
  37. package/src/generators/fastify/project-generator.js +373 -0
  38. package/src/generators/fastify/prompts.js +76 -0
  39. package/src/generators/fastify/templates/app.js +179 -0
  40. package/src/generators/fastify/templates/config.js +33 -0
  41. package/src/generators/fastify/templates/docker.js +73 -0
  42. package/src/generators/fastify/templates/models.js +77 -0
  43. package/src/generators/fastify/templates/package-json.js +57 -0
  44. package/src/generators/fastify/templates/plugins.js +38 -0
  45. package/src/generators/fastify/templates/readme.js +328 -0
  46. package/src/generators/fastify/templates/routes.js +32 -0
  47. package/src/generators/fastify/templates/server.js +71 -0
  48. package/src/generators/fastify/templates/services.js +50 -0
  49. package/src/generators/fastify/templates/tests.js +60 -0
  50. package/src/generators/nextjs/dependency-manager.js +99 -0
  51. package/src/generators/nextjs/file-generator.js +256 -0
  52. package/src/generators/nextjs/nextjs-generator.js +177 -0
  53. package/src/generators/nextjs/nextjs-project-generator.js +896 -0
  54. package/src/generators/nextjs/package-mappings.js +51 -0
  55. package/src/generators/nextjs/templates.js +272 -0
  56. package/src/generators/package-json-generator.js +117 -0
  57. package/src/generators/vite/components/CreditComponent.jsx +41 -0
  58. package/src/generators/vite/components/app-component.js +359 -0
  59. package/src/generators/vite/components/main-file.js +88 -0
  60. package/src/generators/vite/eslint-config-generator.js +20 -0
  61. package/src/generators/vite/file-generator.js +796 -0
  62. package/src/generators/vite/prettier-config-generator.js +10 -0
  63. package/src/generators/vite/structures/domain-driven-structure.js +465 -0
  64. package/src/generators/vite/structures/feature-based-structure.js +342 -0
  65. package/src/generators/vite/structures/simple-structure.js +62 -0
  66. package/src/generators/vite/styles/index-css.js +130 -0
  67. package/src/generators/vite/tailwind-config-generator.js +14 -0
  68. package/src/generators/vite/vite-config-generator.js +22 -0
  69. package/src/generators/vite/vite-project-generator.js +263 -0
  70. package/src/generators/vite-project-generator.js +136 -0
  71. package/src/prompts/index.js +262 -0
  72. package/src/types/index.js +113 -0
  73. package/src/utils/answer-helpers.js +24 -0
  74. package/src/utils/credits.js +192 -0
  75. package/src/utils/dependencies.js +25 -0
  76. package/src/utils/messages.js +27 -0
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Express.js project structure generator
3
+ */
4
+
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+ import { logger } from '../../core/logger.js';
8
+ import { packageManager } from '../../core/package-manager.js';
9
+ import { featurePackageMap, frameworkBasePackages } from '../../config/package-mappings.js';
10
+ import { FRAMEWORKS, FEATURES, DATABASES, AUTH_STRATEGIES } from '../../types/index.js';
11
+ import { generatePackageJson } from './templates/package-json.js';
12
+ import { generateAppJs } from './templates/app.js';
13
+ import { generateServerJs } from './templates/server.js';
14
+ import { generateRoutes } from './templates/routes.js';
15
+ import { generateMiddleware } from './templates/middleware.js';
16
+ import { generateConfig } from './templates/config.js';
17
+ import { generateModels } from './templates/models.js';
18
+ import { generateControllers } from './templates/controllers.js';
19
+ import { generateServices } from './templates/services.js';
20
+ import { generateTests } from './templates/tests.js';
21
+ import { generateDocker } from './templates/docker.js';
22
+ import { generateReadme } from './templates/readme.js';
23
+
24
+ export async function generateExpressProject(projectPath, answers) {
25
+ const spinner = logger.startSpinner('Generating Express.js project structure...');
26
+
27
+ try {
28
+ logger.info('Creating project directory...');
29
+ await fs.ensureDir(projectPath);
30
+
31
+ logger.info('Generating package.json...');
32
+ const packageJson = generatePackageJson(answers);
33
+ await fs.writeJSON(path.join(projectPath, 'package.json'), packageJson, { spaces: 2 });
34
+
35
+ logger.info('Generating main application files...');
36
+ await generateAppJs(projectPath, answers);
37
+ await generateServerJs(projectPath, answers);
38
+
39
+ // Generate project structure based on choice
40
+ switch (answers.projectStructure) {
41
+ case 'simple':
42
+ await generateSimpleStructure(projectPath, answers);
43
+ break;
44
+ case 'modular':
45
+ await generateModularStructure(projectPath, answers);
46
+ break;
47
+ case 'layered':
48
+ await generateLayeredStructure(projectPath, answers);
49
+ break;
50
+ }
51
+
52
+ // Generate database models if needed
53
+ if (answers.database !== 'none') {
54
+ const modelsContent = generateModels(projectPath, answers);
55
+ await fs.ensureDir(path.join(projectPath, 'src', 'models'));
56
+ await fs.writeFile(path.join(projectPath, 'src', 'models', 'index.js'), modelsContent);
57
+ }
58
+
59
+ logger.info('Generating additional files...');
60
+ // Generate additional files
61
+ const middlewareContent = generateMiddleware(projectPath, answers);
62
+ const routesContent = generateRoutes(projectPath, answers);
63
+ const configContent = generateConfig(projectPath, answers);
64
+ const controllersContent = generateControllers(projectPath, answers);
65
+ const servicesContent = generateServices(projectPath, answers);
66
+
67
+ logger.info('Writing middleware files...');
68
+ // Write middleware files
69
+ await fs.ensureDir(path.join(projectPath, 'src', 'middleware'));
70
+ await fs.writeFile(path.join(projectPath, 'src', 'middleware', 'index.js'), middlewareContent);
71
+
72
+ logger.info('Writing routes files...');
73
+ // Write routes files
74
+ await fs.ensureDir(path.join(projectPath, 'src', 'routes'));
75
+ await fs.writeFile(path.join(projectPath, 'src', 'routes', 'index.js'), routesContent);
76
+
77
+ logger.info('Writing config files...');
78
+ // Write config files
79
+ await fs.ensureDir(path.join(projectPath, 'src', 'config'));
80
+ await fs.writeFile(path.join(projectPath, 'src', 'config', 'index.js'), configContent);
81
+
82
+ logger.info('Writing controllers files...');
83
+ // Write controllers files
84
+ await fs.ensureDir(path.join(projectPath, 'src', 'controllers'));
85
+ await fs.writeFile(path.join(projectPath, 'src', 'controllers', 'index.js'), controllersContent);
86
+
87
+ logger.info('Writing services files...');
88
+ // Write services files
89
+ await fs.ensureDir(path.join(projectPath, 'src', 'services'));
90
+ await fs.writeFile(path.join(projectPath, 'src', 'services', 'index.js'), servicesContent);
91
+
92
+ // Generate tests if requested
93
+ if (answers.includeTests) {
94
+ const testsContent = generateTests(projectPath, answers);
95
+ await fs.ensureDir(path.join(projectPath, 'tests'));
96
+ await fs.writeFile(path.join(projectPath, 'tests', 'app.test.js'), testsContent);
97
+ }
98
+
99
+ // Generate Docker files if requested
100
+ if (answers.includeDocker) {
101
+ const { dockerfile, dockerCompose } = generateDocker(projectPath, answers);
102
+ await fs.writeFile(path.join(projectPath, 'Dockerfile'), dockerfile);
103
+ await fs.writeFile(path.join(projectPath, 'docker-compose.yml'), dockerCompose);
104
+ }
105
+
106
+ logger.info('Generating README...');
107
+ // Generate README
108
+ await generateReadme(projectPath, answers);
109
+
110
+ logger.info('Generating .gitignore...');
111
+ // Generate .gitignore
112
+ await generateGitignore(projectPath);
113
+
114
+ logger.info('Generating .env.example...');
115
+ // Generate .env.example
116
+ await generateEnvExample(projectPath, answers);
117
+
118
+ spinner.succeed('Project structure generated successfully!');
119
+
120
+ // Skip dependency installation for now - let user install manually
121
+ logger.info('Project structure created! Next steps:');
122
+ logger.info(` cd ${path.basename(projectPath)}`);
123
+ logger.info(' npm install');
124
+ logger.info(' npm run dev');
125
+
126
+ } catch (error) {
127
+ spinner.fail('Failed to generate project structure');
128
+ throw error;
129
+ }
130
+ }
131
+
132
+ async function generateSimpleStructure(projectPath, answers) {
133
+ const srcDir = path.join(projectPath, 'src');
134
+ await fs.ensureDir(srcDir);
135
+
136
+ // Create basic structure
137
+ await fs.ensureDir(path.join(srcDir, 'routes'));
138
+ await fs.ensureDir(path.join(srcDir, 'middleware'));
139
+ await fs.ensureDir(path.join(srcDir, 'utils'));
140
+ }
141
+
142
+ async function generateModularStructure(projectPath, answers) {
143
+ const srcDir = path.join(projectPath, 'src');
144
+ await fs.ensureDir(srcDir);
145
+
146
+ // Create modular structure
147
+ const modules = ['auth', 'users', 'api'];
148
+ for (const module of modules) {
149
+ await fs.ensureDir(path.join(srcDir, 'modules', module, 'routes'));
150
+ await fs.ensureDir(path.join(srcDir, 'modules', module, 'controllers'));
151
+ await fs.ensureDir(path.join(srcDir, 'modules', module, 'services'));
152
+ await fs.ensureDir(path.join(srcDir, 'modules', module, 'models'));
153
+ }
154
+
155
+ await fs.ensureDir(path.join(srcDir, 'shared', 'middleware'));
156
+ await fs.ensureDir(path.join(srcDir, 'shared', 'utils'));
157
+ await fs.ensureDir(path.join(srcDir, 'shared', 'config'));
158
+ }
159
+
160
+ async function generateLayeredStructure(projectPath, answers) {
161
+ const srcDir = path.join(projectPath, 'src');
162
+ await fs.ensureDir(srcDir);
163
+
164
+ // Create layered structure
165
+ await fs.ensureDir(path.join(srcDir, 'controllers'));
166
+ await fs.ensureDir(path.join(srcDir, 'services'));
167
+ await fs.ensureDir(path.join(srcDir, 'repositories'));
168
+ await fs.ensureDir(path.join(srcDir, 'models'));
169
+ await fs.ensureDir(path.join(srcDir, 'routes'));
170
+ await fs.ensureDir(path.join(srcDir, 'middleware'));
171
+ await fs.ensureDir(path.join(srcDir, 'utils'));
172
+ await fs.ensureDir(path.join(srcDir, 'config'));
173
+ }
174
+
175
+ async function generateGitignore(projectPath) {
176
+ const gitignore = `# Dependencies
177
+ node_modules/
178
+ npm-debug.log*
179
+ yarn-debug.log*
180
+ yarn-error.log*
181
+ pnpm-debug.log*
182
+
183
+ # Environment variables
184
+ .env
185
+ .env.local
186
+ .env.development.local
187
+ .env.test.local
188
+ .env.production.local
189
+
190
+ # Logs
191
+ logs
192
+ *.log
193
+
194
+ # Runtime data
195
+ pids
196
+ *.pid
197
+ *.seed
198
+ *.pid.lock
199
+
200
+ # Coverage directory used by tools like istanbul
201
+ coverage/
202
+ *.lcov
203
+
204
+ # nyc test coverage
205
+ .nyc_output
206
+
207
+ # Dependency directories
208
+ node_modules/
209
+ jspm_packages/
210
+
211
+ # Optional npm cache directory
212
+ .npm
213
+
214
+ # Optional eslint cache
215
+ .eslintcache
216
+
217
+ # Optional REPL history
218
+ .node_repl_history
219
+
220
+ # Output of 'npm pack'
221
+ *.tgz
222
+
223
+ # Yarn Integrity file
224
+ .yarn-integrity
225
+
226
+ # dotenv environment variables file
227
+ .env
228
+ .env.test
229
+
230
+ # parcel-bundler cache (https://parceljs.org/)
231
+ .cache
232
+ .parcel-cache
233
+
234
+ # next.js build output
235
+ .next
236
+
237
+ # nuxt.js build output
238
+ .nuxt
239
+
240
+ # vuepress build output
241
+ .vuepress/dist
242
+
243
+ # Serverless directories
244
+ .serverless/
245
+
246
+ # FuseBox cache
247
+ .fusebox/
248
+
249
+ # DynamoDB Local files
250
+ .dynamodb/
251
+
252
+ # TernJS port file
253
+ .tern-port
254
+
255
+ # IDE
256
+ .vscode/
257
+ .idea/
258
+ *.swp
259
+ *.swo
260
+
261
+ # OS
262
+ .DS_Store
263
+ Thumbs.db
264
+
265
+ # Build output
266
+ dist/
267
+ build/
268
+ `;
269
+
270
+ await fs.writeFile(path.join(projectPath, '.gitignore'), gitignore);
271
+ }
272
+
273
+ async function generateEnvExample(projectPath, answers) {
274
+ let envContent = `# Server Configuration
275
+ PORT=3000
276
+ NODE_ENV=development
277
+
278
+ # Database Configuration
279
+ `;
280
+
281
+ if (answers.database === DATABASES.MONGODB) {
282
+ envContent += `MONGODB_URI=mongodb://localhost:27017/${answers.projectName}
283
+ `;
284
+ } else if (answers.database === DATABASES.POSTGRESQL) {
285
+ envContent += `DATABASE_URL=postgresql://username:password@localhost:5432/${answers.projectName}
286
+ `;
287
+ } else if (answers.database === DATABASES.MYSQL) {
288
+ envContent += `DB_HOST=localhost
289
+ DB_PORT=3306
290
+ DB_NAME=${answers.projectName}
291
+ DB_USER=root
292
+ DB_PASSWORD=password
293
+ `;
294
+ } else if (answers.database === DATABASES.SQLITE) {
295
+ envContent += `DATABASE_URL=file:./dev.db
296
+ `;
297
+ }
298
+
299
+ if (answers.authStrategy && answers.authStrategy !== 'none') {
300
+ envContent += `
301
+ # Authentication
302
+ JWT_SECRET=your-super-secret-jwt-key
303
+ JWT_EXPIRES_IN=7d
304
+ `;
305
+ }
306
+
307
+ if (answers.features.includes(FEATURES.CORS)) {
308
+ envContent += `
309
+ # CORS
310
+ CORS_ORIGIN=http://localhost:3000
311
+ `;
312
+ }
313
+
314
+ await fs.writeFile(path.join(projectPath, '.env.example'), envContent);
315
+ }
316
+
317
+ async function installDependencies(projectPath, answers) {
318
+ const packages = [];
319
+
320
+ // Add base Express packages
321
+ const basePackages = frameworkBasePackages[FRAMEWORKS.EXPRESS];
322
+ packages.push(...basePackages.deps.map(name => ({ name, version: 'latest', dev: false })));
323
+ packages.push(...basePackages.devDeps.map(name => ({ name, version: 'latest', dev: true })));
324
+
325
+ // Add database packages
326
+ if (answers.database === DATABASES.MONGODB) {
327
+ packages.push({ name: 'mongoose', version: 'latest', dev: false });
328
+ } else if (answers.database === DATABASES.POSTGRESQL || answers.database === DATABASES.SQLITE) {
329
+ packages.push({ name: '@prisma/client', version: 'latest', dev: false });
330
+ packages.push({ name: 'prisma', version: 'latest', dev: true });
331
+ } else if (answers.database === DATABASES.MYSQL) {
332
+ packages.push({ name: 'sequelize', version: 'latest', dev: false });
333
+ packages.push({ name: 'mysql2', version: 'latest', dev: false });
334
+ }
335
+
336
+ // Add authentication packages
337
+ if (answers.authStrategy === AUTH_STRATEGIES.JWT) {
338
+ packages.push({ name: 'jsonwebtoken', version: 'latest', dev: false });
339
+ packages.push({ name: 'bcryptjs', version: 'latest', dev: false });
340
+ } else if (answers.authStrategy === AUTH_STRATEGIES.OAUTH) {
341
+ packages.push({ name: 'passport', version: 'latest', dev: false });
342
+ packages.push({ name: 'passport-local', version: 'latest', dev: false });
343
+ packages.push({ name: 'express-session', version: 'latest', dev: false });
344
+ }
345
+
346
+ // Add feature packages
347
+ for (const feature of answers.features || []) {
348
+ const featureInfo = featurePackageMap[feature];
349
+ if (featureInfo) {
350
+ if (featureInfo.deps) {
351
+ packages.push(...featureInfo.deps.map(name => ({ name, version: 'latest', dev: false })));
352
+ }
353
+ if (featureInfo.devDeps) {
354
+ packages.push(...featureInfo.devDeps.map(name => ({ name, version: 'latest', dev: true })));
355
+ }
356
+ }
357
+ }
358
+
359
+ // Add testing packages if requested
360
+ if (answers.includeTests) {
361
+ packages.push({ name: 'jest', version: 'latest', dev: true });
362
+ packages.push({ name: 'supertest', version: 'latest', dev: true });
363
+ packages.push({ name: '@types/jest', version: 'latest', dev: true });
364
+ }
365
+
366
+ await packageManager.installDependencies(projectPath, packages);
367
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Express.js specific prompts
3
+ */
4
+
5
+ import { FRAMEWORKS, FEATURES, DATABASES, AUTH_STRATEGIES } from '../../types/index.js';
6
+
7
+ export function getExpressPrompts(answers) {
8
+ return [
9
+ {
10
+ type: 'list',
11
+ name: 'database',
12
+ message: 'Choose a database:',
13
+ choices: [
14
+ { name: 'MongoDB (with Mongoose)', value: DATABASES.MONGODB },
15
+ { name: 'PostgreSQL (with Prisma)', value: DATABASES.POSTGRESQL },
16
+ { name: 'MySQL (with Sequelize)', value: DATABASES.MYSQL },
17
+ { name: 'SQLite (with Prisma)', value: DATABASES.SQLITE },
18
+ { name: 'None', value: 'none' }
19
+ ],
20
+ default: DATABASES.MONGODB
21
+ },
22
+ {
23
+ type: 'list',
24
+ name: 'authStrategy',
25
+ message: 'Choose authentication strategy:',
26
+ choices: [
27
+ { name: 'JWT (JSON Web Tokens)', value: AUTH_STRATEGIES.JWT },
28
+ { name: 'Session-based', value: AUTH_STRATEGIES.SESSION },
29
+ { name: 'OAuth (Passport.js)', value: AUTH_STRATEGIES.OAUTH },
30
+ { name: 'None', value: 'none' }
31
+ ],
32
+ default: AUTH_STRATEGIES.JWT,
33
+ when: (answers) => answers.database !== 'none'
34
+ },
35
+ {
36
+ type: 'checkbox',
37
+ name: 'features',
38
+ message: 'Select additional features:',
39
+ choices: [
40
+ { name: 'CORS middleware', value: FEATURES.CORS },
41
+ { name: 'Security headers (Helmet)', value: FEATURES.HELMET },
42
+ { name: 'Request logging (Morgan)', value: FEATURES.MORGAN },
43
+ { name: 'Winston logger', value: FEATURES.WINSTON },
44
+ { name: 'Request validation', value: FEATURES.EXPRESS_VALIDATOR },
45
+ { name: 'API documentation (Swagger)', value: FEATURES.SWAGGER },
46
+ { name: 'Environment variables (.env)', value: FEATURES.DOTENV }
47
+ ],
48
+ default: [FEATURES.CORS, FEATURES.HELMET, FEATURES.MORGAN, FEATURES.DOTENV]
49
+ },
50
+ {
51
+ type: 'list',
52
+ name: 'projectStructure',
53
+ message: 'Choose project structure:',
54
+ choices: [
55
+ { name: 'Simple (Basic structure)', value: 'simple' },
56
+ { name: 'Modular (Organized by features)', value: 'modular' },
57
+ { name: 'Layered (Controller-Service-Repository)', value: 'layered' }
58
+ ],
59
+ default: 'modular'
60
+ },
61
+ {
62
+ type: 'confirm',
63
+ name: 'includeTests',
64
+ message: 'Include testing setup?',
65
+ default: true
66
+ },
67
+ {
68
+ type: 'confirm',
69
+ name: 'includeDocker',
70
+ message: 'Include Docker configuration?',
71
+ default: false
72
+ }
73
+ ];
74
+ }