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