openwork-agent 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/LICENSE +21 -0
- package/README.md +436 -0
- package/package.json +78 -0
- package/src/core/TechDetector.js +351 -0
- package/src/generators/ProjectGenerator.js +1241 -0
- package/src/generators/ProjectGeneratorExtensions.js +14 -0
- package/src/generators/TemplateMethods.js +402 -0
- package/src/generators/index.js +5 -0
- package/src/index.js +152 -0
- package/src/main.js +8 -0
- package/src/templates/common/README.md.hbs +358 -0
- package/src/templates/docker/index.js +518 -0
- package/src/templates/docker.js +58 -0
- package/src/templates/go/basic/api/routes/user.go.hbs +138 -0
- package/src/templates/go/basic/config/config.go.hbs +54 -0
- package/src/templates/go/basic/go.mod.hbs +8 -0
- package/src/templates/go/basic/main.go.hbs +70 -0
- package/src/templates/go/basic/models/user.go.hbs +69 -0
- package/src/templates/go/basic/services/user_service.go.hbs +173 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/controller/UserController.java.hbs +91 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/dto/ApiResponse.java.hbs +40 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/model/User.java.hbs +102 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/repository/UserRepository.java.hbs +20 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/service/UserService.java.hbs +65 -0
- package/src/templates/java/basic/src/main/java/com/{{snakeCase projectName}}/{{projectName}}/{{pascalCase projectName}}Application.java.hbs +16 -0
- package/src/templates/node/basic/src/config/database.ts.hbs +18 -0
- package/src/templates/node/basic/src/controllers/UserController.ts.hbs +98 -0
- package/src/templates/node/basic/src/index.ts.hbs +45 -0
- package/src/templates/node/basic/src/middleware/errorHandler.ts.hbs +33 -0
- package/src/templates/node/basic/src/routes/index.ts.hbs +42 -0
- package/src/templates/node/basic/src/types/index.ts.hbs +18 -0
- package/src/templates/python/basic/config/database.py.hbs +36 -0
- package/src/templates/python/basic/main.py.hbs +58 -0
- package/src/templates/python/basic/middleware/error_handler.py.hbs +41 -0
- package/src/templates/python/basic/models/user.py.hbs +40 -0
- package/src/templates/python/basic/routes/__init__.py.hbs +12 -0
- package/src/templates/python/basic/routes/users.py.hbs +64 -0
- package/src/templates/rust/basic/Cargo.toml.hbs +39 -0
- package/src/templates/rust/basic/src/config/database.rs.hbs +27 -0
- package/src/templates/rust/basic/src/handlers/user.rs.hbs +130 -0
- package/src/templates/rust/basic/src/handlers/user_routes.rs.hbs +15 -0
- package/src/templates/rust/basic/src/main.rs.hbs +53 -0
- package/src/templates/rust/basic/src/models/mod.rs.hbs +79 -0
- package/src/templates/rust/basic/src/schema.rs.hbs +10 -0
- package/src/utils/FileManager.js +186 -0
- package/src/utils/Templates.js +231 -0
|
@@ -0,0 +1,1241 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const ora = require('ora');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const FileManager = require('../utils/FileManager');
|
|
8
|
+
const TechDetector = require('../core/TechDetector');
|
|
9
|
+
|
|
10
|
+
class ProjectGenerator {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.fileManager = new FileManager();
|
|
13
|
+
this.techDetector = new TechDetector();
|
|
14
|
+
this.templatesPath = path.join(__dirname, '../templates');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async promptForConfiguration(config) {
|
|
18
|
+
const questions = [];
|
|
19
|
+
|
|
20
|
+
// Technology selection
|
|
21
|
+
if (!config.technology) {
|
|
22
|
+
const technologies = this.techDetector.getAvailableTechnologies();
|
|
23
|
+
const recommended = this.techDetector.getRecommendedTechStack();
|
|
24
|
+
|
|
25
|
+
questions.push({
|
|
26
|
+
type: 'list',
|
|
27
|
+
name: 'technology',
|
|
28
|
+
message: 'Choose your technology stack:',
|
|
29
|
+
choices: [
|
|
30
|
+
...technologies.map(tech => ({
|
|
31
|
+
name: `${tech.toUpperCase()} - ${recommended[tech]?.reason || 'Popular backend technology'}`,
|
|
32
|
+
value: tech
|
|
33
|
+
})),
|
|
34
|
+
new inquirer.Separator()
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Framework selection (after technology is known)
|
|
40
|
+
const tech = config.technology || (await inquirer.prompt([{
|
|
41
|
+
type: 'list',
|
|
42
|
+
name: 'technology',
|
|
43
|
+
message: 'Choose your technology stack:',
|
|
44
|
+
choices: this.techDetector.getAvailableTechnologies()
|
|
45
|
+
}])).technology;
|
|
46
|
+
|
|
47
|
+
const frameworks = this.techDetector.getFrameworksForTechnology(tech);
|
|
48
|
+
if (frameworks.length > 0 && !config.framework) {
|
|
49
|
+
questions.push({
|
|
50
|
+
type: 'list',
|
|
51
|
+
name: 'framework',
|
|
52
|
+
message: `Choose ${tech} framework:`,
|
|
53
|
+
choices: [
|
|
54
|
+
...frameworks.map(fw => fw.toUpperCase()),
|
|
55
|
+
{ name: 'None/Custom', value: null }
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Database selection
|
|
61
|
+
if (!config.database) {
|
|
62
|
+
const databases = this.techDetector.getAvailableDatabases();
|
|
63
|
+
questions.push({
|
|
64
|
+
type: 'list',
|
|
65
|
+
name: 'database',
|
|
66
|
+
message: 'Choose your database:',
|
|
67
|
+
choices: [
|
|
68
|
+
...databases.map(db => db.toUpperCase()),
|
|
69
|
+
{ name: 'None/No database', value: null }
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Additional options
|
|
75
|
+
if (!config.template) {
|
|
76
|
+
questions.push({
|
|
77
|
+
type: 'list',
|
|
78
|
+
name: 'template',
|
|
79
|
+
message: 'Choose project template:',
|
|
80
|
+
choices: [
|
|
81
|
+
{ name: 'Basic REST API', value: 'api' },
|
|
82
|
+
{ name: 'Full CRUD App', value: 'crud' },
|
|
83
|
+
{ name: 'Microservice', value: 'microservice' },
|
|
84
|
+
{ name: 'GraphQL API', value: 'graphql' },
|
|
85
|
+
{ name: 'Minimal', value: 'minimal' }
|
|
86
|
+
]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
questions.push(
|
|
91
|
+
{
|
|
92
|
+
type: 'confirm',
|
|
93
|
+
name: 'includeDocker',
|
|
94
|
+
message: 'Include Docker configuration?',
|
|
95
|
+
default: true
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: 'confirm',
|
|
99
|
+
name: 'includeTests',
|
|
100
|
+
message: 'Include test setup?',
|
|
101
|
+
default: true
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: 'confirm',
|
|
105
|
+
name: 'includeCI',
|
|
106
|
+
message: 'Include CI/CD configuration?',
|
|
107
|
+
default: false
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'input',
|
|
111
|
+
name: 'author',
|
|
112
|
+
message: 'Author name:',
|
|
113
|
+
default: 'OpenWork Agent'
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
type: 'input',
|
|
117
|
+
name: 'description',
|
|
118
|
+
message: 'Project description:',
|
|
119
|
+
default: `${config.projectName} - Backend application`
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const answers = await inquirer.prompt(questions);
|
|
124
|
+
return { ...config, ...answers };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async createProject(config) {
|
|
128
|
+
const spinner = ora('Creating project...').start();
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const projectPath = path.resolve(process.cwd(), config.projectName);
|
|
132
|
+
|
|
133
|
+
// Check if directory already exists
|
|
134
|
+
if (await fs.pathExists(projectPath)) {
|
|
135
|
+
throw new Error(`Directory ${config.projectName} already exists`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Create project directory
|
|
139
|
+
await fs.ensureDir(projectPath);
|
|
140
|
+
spinner.text = 'Setting up project structure...';
|
|
141
|
+
|
|
142
|
+
// Generate project structure
|
|
143
|
+
await this.generateProjectStructure(projectPath, config);
|
|
144
|
+
|
|
145
|
+
// Copy template files
|
|
146
|
+
await this.copyTemplateFiles(projectPath, config);
|
|
147
|
+
|
|
148
|
+
// Generate configuration files
|
|
149
|
+
await this.generateConfiguration(projectPath, config);
|
|
150
|
+
|
|
151
|
+
// Generate Docker files if requested
|
|
152
|
+
if (config.includeDocker) {
|
|
153
|
+
await this.generateDockerFiles(projectPath, config);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Generate CI/CD if requested
|
|
157
|
+
if (config.includeCI) {
|
|
158
|
+
await this.generateCIFiles(projectPath, config);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
spinner.succeed(`Project ${config.projectName} created successfully!`);
|
|
162
|
+
|
|
163
|
+
// Show next steps
|
|
164
|
+
this.showNextSteps(config);
|
|
165
|
+
|
|
166
|
+
} catch (error) {
|
|
167
|
+
spinner.fail('Failed to create project');
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async generateProjectStructure(projectPath, config) {
|
|
173
|
+
const structure = this.getProjectStructure(config);
|
|
174
|
+
|
|
175
|
+
for (const dir of structure.directories) {
|
|
176
|
+
await fs.ensureDir(path.join(projectPath, dir));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Create basic files
|
|
180
|
+
for (const [filename, content] of Object.entries(structure.files || {})) {
|
|
181
|
+
await fs.writeFile(
|
|
182
|
+
path.join(projectPath, filename),
|
|
183
|
+
typeof content === 'function' ? content(config) : content
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
getProjectStructure(config) {
|
|
189
|
+
const baseStructure = {
|
|
190
|
+
directories: [
|
|
191
|
+
'src',
|
|
192
|
+
'src/controllers',
|
|
193
|
+
'src/models',
|
|
194
|
+
'src/routes',
|
|
195
|
+
'src/middleware',
|
|
196
|
+
'src/services',
|
|
197
|
+
'src/utils',
|
|
198
|
+
'src/config',
|
|
199
|
+
'tests',
|
|
200
|
+
'docs'
|
|
201
|
+
],
|
|
202
|
+
files: {
|
|
203
|
+
'.gitignore': this.generateGitignore(config),
|
|
204
|
+
'README.md': () => this.generateReadme(config)
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Add technology-specific structure
|
|
209
|
+
const techStructure = this.getTechnologySpecificStructure(config);
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
directories: [...baseStructure.directories, ...techStructure.directories],
|
|
213
|
+
files: { ...baseStructure.files, ...techStructure.files }
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
getTechnologySpecificStructure(config) {
|
|
218
|
+
const structures = {
|
|
219
|
+
node: {
|
|
220
|
+
directories: ['src/types', 'src/interfaces', 'src/dto'],
|
|
221
|
+
files: {
|
|
222
|
+
'package.json': () => this.generatePackageJSON(config),
|
|
223
|
+
'tsconfig.json': () => this.generateTsConfig(config),
|
|
224
|
+
'.env.example': this.generateEnvExample(config)
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
python: {
|
|
228
|
+
directories: ['src/api', 'src/db', 'migrations'],
|
|
229
|
+
files: {
|
|
230
|
+
'requirements.txt': () => this.generateRequirements(config),
|
|
231
|
+
'setup.py': () => this.generateSetupPy(config),
|
|
232
|
+
'.env.example': this.generateEnvExample(config)
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
java: {
|
|
236
|
+
directories: ['src/main/java', 'src/main/resources', 'src/test/java'],
|
|
237
|
+
files: {
|
|
238
|
+
'pom.xml': () => this.generatePomXML(config),
|
|
239
|
+
'src/main/resources/application.properties': () => this.generateApplicationProperties(config)
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
go: {
|
|
243
|
+
directories: ['internal', 'pkg', 'cmd', 'api'],
|
|
244
|
+
files: {
|
|
245
|
+
'go.mod': () => this.generateGoMod(config),
|
|
246
|
+
'main.go': () => this.generateMainGo(config)
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
rust: {
|
|
250
|
+
directories: ['src/bin', 'tests'],
|
|
251
|
+
files: {
|
|
252
|
+
'Cargo.toml': () => this.generateCargoToml(config),
|
|
253
|
+
'src/main.rs': () => this.generateMainRs(config)
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
php: {
|
|
257
|
+
directories: ['app/Http/Controllers', 'app/Models', 'database/migrations', 'routes'],
|
|
258
|
+
files: {
|
|
259
|
+
'composer.json': () => this.generateComposerJSON(config),
|
|
260
|
+
'.env.example': this.generateEnvExample(config)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
return structures[config.technology] || { directories: [], files: {} };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async copyTemplateFiles(projectPath, config) {
|
|
269
|
+
const templatePath = path.join(this.templatesPath, config.technology);
|
|
270
|
+
|
|
271
|
+
if (!await fs.pathExists(templatePath)) {
|
|
272
|
+
console.log(chalk.yellow(`Warning: No templates found for ${config.technology}`));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const frameworkPath = config.framework ?
|
|
277
|
+
path.join(templatePath, config.framework) :
|
|
278
|
+
path.join(templatePath, 'basic');
|
|
279
|
+
|
|
280
|
+
if (await fs.pathExists(frameworkPath)) {
|
|
281
|
+
await this.fileManager.copyDirectory(frameworkPath, projectPath, config);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async generateConfiguration(projectPath, config) {
|
|
286
|
+
// Generate config files
|
|
287
|
+
const configPath = path.join(projectPath, 'src/config');
|
|
288
|
+
|
|
289
|
+
switch (config.technology) {
|
|
290
|
+
case 'node':
|
|
291
|
+
await this.generateNodeConfig(configPath, config);
|
|
292
|
+
break;
|
|
293
|
+
case 'python':
|
|
294
|
+
await this.generatePythonConfig(configPath, config);
|
|
295
|
+
break;
|
|
296
|
+
case 'java':
|
|
297
|
+
await this.generateJavaConfig(projectPath, config);
|
|
298
|
+
break;
|
|
299
|
+
case 'go':
|
|
300
|
+
await this.generateGoConfig(projectPath, config);
|
|
301
|
+
break;
|
|
302
|
+
case 'rust':
|
|
303
|
+
await this.generateRustConfig(projectPath, config);
|
|
304
|
+
break;
|
|
305
|
+
case 'php':
|
|
306
|
+
await this.generatePhpConfig(projectPath, config);
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async generateDockerFiles(projectPath, config) {
|
|
312
|
+
const dockerConfigs = {
|
|
313
|
+
node: this.generateDockerfileNode,
|
|
314
|
+
python: this.generateDockerfilePython,
|
|
315
|
+
java: this.generateDockerfileJava,
|
|
316
|
+
go: this.generateDockerfileGo,
|
|
317
|
+
rust: this.generateDockerfileRust,
|
|
318
|
+
php: this.generateDockerfilePhp
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const dockerfile = dockerConfigs[config.technology];
|
|
322
|
+
if (dockerfile) {
|
|
323
|
+
await fs.writeFile(
|
|
324
|
+
path.join(projectPath, 'Dockerfile'),
|
|
325
|
+
dockerfile.call(this, config)
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Generate docker-compose.yml if database is selected
|
|
330
|
+
if (config.database) {
|
|
331
|
+
await fs.writeFile(
|
|
332
|
+
path.join(projectPath, 'docker-compose.yml'),
|
|
333
|
+
this.generateDockerCompose(config)
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Generate .dockerignore
|
|
338
|
+
await fs.writeFile(
|
|
339
|
+
path.join(projectPath, '.dockerignore'),
|
|
340
|
+
this.generateDockerignore(config)
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
getSetupCommands(technology) {
|
|
345
|
+
const commands = {
|
|
346
|
+
node: ['npm install', 'npm run dev'],
|
|
347
|
+
python: ['python -m venv venv', 'source venv/bin/activate', 'pip install -r requirements.txt', 'uvicorn main:app --reload'],
|
|
348
|
+
java: ['mvn clean install', 'mvn spring-boot:run'],
|
|
349
|
+
go: ['go mod download', 'go run main.go'],
|
|
350
|
+
rust: ['cargo build', 'cargo run'],
|
|
351
|
+
php: ['composer install', 'php artisan serve']
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
return commands[technology] || ['echo "Setup commands not defined for this technology"'];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
showNextSteps(config) {
|
|
358
|
+
console.log(chalk.cyan('\n📋 Next Steps:'));
|
|
359
|
+
console.log(chalk.white(` cd ${config.projectName}`));
|
|
360
|
+
|
|
361
|
+
this.getSetupCommands(config.technology).forEach(cmd => {
|
|
362
|
+
console.log(chalk.white(` ${cmd}`));
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
if (config.includeDocker) {
|
|
366
|
+
console.log(chalk.white(' docker-compose up'));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
console.log(chalk.green('\n✨ Happy coding!'));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Template generation methods
|
|
373
|
+
generatePackageJSON(config) {
|
|
374
|
+
return JSON.stringify({
|
|
375
|
+
name: config.projectName,
|
|
376
|
+
version: '1.0.0',
|
|
377
|
+
description: config.description,
|
|
378
|
+
main: 'dist/index.js',
|
|
379
|
+
scripts: {
|
|
380
|
+
dev: 'nodemon src/index.ts',
|
|
381
|
+
build: 'tsc',
|
|
382
|
+
start: 'node dist/index.js',
|
|
383
|
+
test: 'jest',
|
|
384
|
+
'test:watch': 'jest --watch'
|
|
385
|
+
},
|
|
386
|
+
dependencies: this.getNodeDependencies(config),
|
|
387
|
+
devDependencies: this.getNodeDevDependencies(config),
|
|
388
|
+
author: config.author,
|
|
389
|
+
license: 'MIT'
|
|
390
|
+
}, null, 2);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
getNodeDependencies(config) {
|
|
394
|
+
const deps = {
|
|
395
|
+
express: ['express', 'cors', 'helmet'],
|
|
396
|
+
nestjs: ['@nestjs/core', '@nestjs/common', '@nestjs/platform-express'],
|
|
397
|
+
fastify: ['fastify', '@fastify/cors']
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const dbDeps = {
|
|
401
|
+
mongodb: ['mongoose'],
|
|
402
|
+
postgresql: ['pg', 'typeorm'],
|
|
403
|
+
mysql: ['mysql2', 'typeorm'],
|
|
404
|
+
sqlite: ['sqlite3', 'typeorm']
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const frameworkDeps = deps[config.framework] || deps.express;
|
|
408
|
+
const databaseDeps = config.database ? dbDeps[config.database] : [];
|
|
409
|
+
|
|
410
|
+
return [...new Set([...frameworkDeps, ...databaseDeps, 'dotenv'])];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
getNodeDevDependencies(config) {
|
|
414
|
+
return [
|
|
415
|
+
'@types/node',
|
|
416
|
+
'typescript',
|
|
417
|
+
'ts-node',
|
|
418
|
+
'nodemon',
|
|
419
|
+
'jest',
|
|
420
|
+
'@types/jest',
|
|
421
|
+
'ts-jest'
|
|
422
|
+
];
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
generateTsConfig(config) {
|
|
426
|
+
return JSON.stringify({
|
|
427
|
+
compilerOptions: {
|
|
428
|
+
target: 'ES2020',
|
|
429
|
+
module: 'commonjs',
|
|
430
|
+
lib: ['ES2020'],
|
|
431
|
+
outDir: './dist',
|
|
432
|
+
rootDir: './src',
|
|
433
|
+
strict: true,
|
|
434
|
+
esModuleInterop: true,
|
|
435
|
+
skipLibCheck: true,
|
|
436
|
+
forceConsistentCasingInFileNames: true,
|
|
437
|
+
resolveJsonModule: true,
|
|
438
|
+
declaration: true,
|
|
439
|
+
declarationMap: true,
|
|
440
|
+
sourceMap: true
|
|
441
|
+
},
|
|
442
|
+
include: ['src/**/*'],
|
|
443
|
+
exclude: ['node_modules', 'dist', 'tests']
|
|
444
|
+
}, null, 2);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
generateGitignore(config) {
|
|
448
|
+
return `# Dependencies
|
|
449
|
+
node_modules/
|
|
450
|
+
npm-debug.log*
|
|
451
|
+
yarn-debug.log*
|
|
452
|
+
yarn-error.log*
|
|
453
|
+
|
|
454
|
+
# Build output
|
|
455
|
+
dist/
|
|
456
|
+
build/
|
|
457
|
+
|
|
458
|
+
# Environment variables
|
|
459
|
+
.env
|
|
460
|
+
.env.local
|
|
461
|
+
.env.development.local
|
|
462
|
+
.env.test.local
|
|
463
|
+
.env.production.local
|
|
464
|
+
|
|
465
|
+
# IDE files
|
|
466
|
+
.vscode/
|
|
467
|
+
.idea/
|
|
468
|
+
*.swp
|
|
469
|
+
*.swo
|
|
470
|
+
|
|
471
|
+
# OS files
|
|
472
|
+
.DS_Store
|
|
473
|
+
Thumbs.db
|
|
474
|
+
|
|
475
|
+
# Logs
|
|
476
|
+
logs/
|
|
477
|
+
*.log
|
|
478
|
+
|
|
479
|
+
# Coverage reports
|
|
480
|
+
coverage/
|
|
481
|
+
.nyc_output/
|
|
482
|
+
|
|
483
|
+
# Database
|
|
484
|
+
*.db
|
|
485
|
+
*.sqlite
|
|
486
|
+
|
|
487
|
+
# Temporary files
|
|
488
|
+
tmp/
|
|
489
|
+
temp/`;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
generateEnvExample(config) {
|
|
493
|
+
return `# Server Configuration
|
|
494
|
+
PORT=3000
|
|
495
|
+
NODE_ENV=development
|
|
496
|
+
|
|
497
|
+
# Database Configuration
|
|
498
|
+
DATABASE_URL=
|
|
499
|
+
DB_NAME=
|
|
500
|
+
|
|
501
|
+
# Security
|
|
502
|
+
JWT_SECRET=your-secret-key-here
|
|
503
|
+
JWT_EXPIRES_IN=7d
|
|
504
|
+
|
|
505
|
+
# CORS
|
|
506
|
+
CORS_ORIGINS=http://localhost:3000,http://localhost:3001
|
|
507
|
+
|
|
508
|
+
# Logging
|
|
509
|
+
LOG_LEVEL=info
|
|
510
|
+
|
|
511
|
+
# External Services
|
|
512
|
+
# API_KEY=
|
|
513
|
+
# WEBHOOK_URL=`;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
generateCargoToml(config) {
|
|
517
|
+
return `[package]
|
|
518
|
+
name = "${config.projectName}"
|
|
519
|
+
version = "0.1.0"
|
|
520
|
+
edition = "2021"
|
|
521
|
+
authors = ["${config.author || 'OpenWork Agent'}"]
|
|
522
|
+
description = "${config.description || 'Rust backend application'}"
|
|
523
|
+
|
|
524
|
+
[dependencies]
|
|
525
|
+
tokio = { version = "1.0", features = ["full"] }
|
|
526
|
+
serde = { version = "1.0", features = ["derive"] }
|
|
527
|
+
serde_json = "1.0"
|
|
528
|
+
actix-web = "4.0"
|
|
529
|
+
actix-cors = "0.6"
|
|
530
|
+
dotenv = "0.15"
|
|
531
|
+
env_logger = "0.10"
|
|
532
|
+
log = "0.4"
|
|
533
|
+
|
|
534
|
+
[dev-dependencies]
|
|
535
|
+
tokio-test = "0.4"
|
|
536
|
+
`;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
generateGoMod(config) {
|
|
540
|
+
return `module ${config.projectName}
|
|
541
|
+
|
|
542
|
+
go 1.21
|
|
543
|
+
|
|
544
|
+
require (
|
|
545
|
+
github.com/gin-gonic/gin v1.9.1
|
|
546
|
+
github.com/joho/godotenv v1.4.0
|
|
547
|
+
github.com/gin-contrib/cors v1.4.0
|
|
548
|
+
gorm.io/gorm v1.25.4
|
|
549
|
+
gorm.io/driver/postgres v1.5.2
|
|
550
|
+
)`;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
generateReadme(config) {
|
|
554
|
+
return `# ${config.projectName}
|
|
555
|
+
|
|
556
|
+
${config.description || 'Backend application'}
|
|
557
|
+
|
|
558
|
+
## Getting Started
|
|
559
|
+
|
|
560
|
+
### Prerequisites
|
|
561
|
+
- Node.js 14+
|
|
562
|
+
- npm or yarn
|
|
563
|
+
|
|
564
|
+
### Installation
|
|
565
|
+
|
|
566
|
+
\`\`\`bash
|
|
567
|
+
npm install
|
|
568
|
+
\`\`\`
|
|
569
|
+
|
|
570
|
+
### Development
|
|
571
|
+
|
|
572
|
+
\`\`\`bash
|
|
573
|
+
npm run dev
|
|
574
|
+
\`\`\`
|
|
575
|
+
|
|
576
|
+
### Build
|
|
577
|
+
|
|
578
|
+
\`\`\`bash
|
|
579
|
+
npm run build
|
|
580
|
+
\`\`\`
|
|
581
|
+
|
|
582
|
+
### Test
|
|
583
|
+
|
|
584
|
+
\`\`\`bash
|
|
585
|
+
npm test
|
|
586
|
+
\`\`\`
|
|
587
|
+
|
|
588
|
+
## API Documentation
|
|
589
|
+
|
|
590
|
+
Visit \`http://localhost:3000/api-docs\` for API documentation.
|
|
591
|
+
|
|
592
|
+
## License
|
|
593
|
+
|
|
594
|
+
MIT
|
|
595
|
+
`;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Additional methods for completeness
|
|
599
|
+
generateRequirements(config) {
|
|
600
|
+
const requirements = [
|
|
601
|
+
'fastapi==0.104.1',
|
|
602
|
+
'uvicorn[standard]==0.24.0',
|
|
603
|
+
'pydantic==2.5.0',
|
|
604
|
+
'python-dotenv==1.0.0'
|
|
605
|
+
];
|
|
606
|
+
|
|
607
|
+
if (config.database === 'postgresql') {
|
|
608
|
+
requirements.push('asyncpg==0.29.0', 'sqlalchemy==2.0.23');
|
|
609
|
+
} else if (config.database === 'mongodb') {
|
|
610
|
+
requirements.push('motor==3.3.2', 'pymongo==4.6.0');
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return requirements.join('\n');
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
generateSetupPy(config) {
|
|
617
|
+
return `from setuptools import setup, find_packages
|
|
618
|
+
|
|
619
|
+
setup(
|
|
620
|
+
name="${config.projectName}",
|
|
621
|
+
version="1.0.0",
|
|
622
|
+
description="${config.description || 'Python backend application'}",
|
|
623
|
+
author="${config.author || 'OpenWork Agent'}",
|
|
624
|
+
packages=find_packages(),
|
|
625
|
+
install_requires=open('requirements.txt').read().splitlines(),
|
|
626
|
+
python_requires=">=3.8",
|
|
627
|
+
)`;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
generatePomXML(config) {
|
|
631
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
632
|
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
633
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
634
|
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
|
635
|
+
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
636
|
+
<modelVersion>4.0.0</modelVersion>
|
|
637
|
+
|
|
638
|
+
<groupId>com.openwork</groupId>
|
|
639
|
+
<artifactId>${config.projectName}</artifactId>
|
|
640
|
+
<version>1.0.0</version>
|
|
641
|
+
<packaging>jar</packaging>
|
|
642
|
+
|
|
643
|
+
<name>${config.projectName}</name>
|
|
644
|
+
<description>${config.description || 'Java backend application'}</description>
|
|
645
|
+
|
|
646
|
+
<parent>
|
|
647
|
+
<groupId>org.springframework.boot</groupId>
|
|
648
|
+
<artifactId>spring-boot-starter-parent</artifactId>
|
|
649
|
+
<version>3.1.5</version>
|
|
650
|
+
</parent>
|
|
651
|
+
|
|
652
|
+
<properties>
|
|
653
|
+
<java.version>17</java.version>
|
|
654
|
+
</properties>
|
|
655
|
+
|
|
656
|
+
<dependencies>
|
|
657
|
+
<dependency>
|
|
658
|
+
<groupId>org.springframework.boot</groupId>
|
|
659
|
+
<artifactId>spring-boot-starter-web</artifactId>
|
|
660
|
+
</dependency>
|
|
661
|
+
<dependency>
|
|
662
|
+
<groupId>org.springframework.boot</groupId>
|
|
663
|
+
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
664
|
+
</dependency>
|
|
665
|
+
<dependency>
|
|
666
|
+
<groupId>org.springframework.boot</groupId>
|
|
667
|
+
<artifactId>spring-boot-starter-test</artifactId>
|
|
668
|
+
<scope>test</scope>
|
|
669
|
+
</dependency>
|
|
670
|
+
</dependencies>
|
|
671
|
+
|
|
672
|
+
<build>
|
|
673
|
+
<plugins>
|
|
674
|
+
<plugin>
|
|
675
|
+
<groupId>org.springframework.boot</groupId>
|
|
676
|
+
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
677
|
+
</plugin>
|
|
678
|
+
</plugins>
|
|
679
|
+
</build>
|
|
680
|
+
</project>`;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
generateApplicationProperties(config) {
|
|
684
|
+
return `# Server Configuration
|
|
685
|
+
server.port=8080
|
|
686
|
+
server.servlet.context-path=/
|
|
687
|
+
|
|
688
|
+
# Database Configuration
|
|
689
|
+
spring.datasource.url=jdbc:postgresql://localhost:5432/${config.projectName}
|
|
690
|
+
spring.datasource.username=postgres
|
|
691
|
+
spring.datasource.password=password
|
|
692
|
+
spring.datasource.driver-class-name=org.postgresql.Driver
|
|
693
|
+
|
|
694
|
+
# JPA Configuration
|
|
695
|
+
spring.jpa.hibernate.ddl-auto=update
|
|
696
|
+
spring.jpa.show-sql=true
|
|
697
|
+
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
|
|
698
|
+
|
|
699
|
+
# Logging
|
|
700
|
+
logging.level.com.openwork=INFO
|
|
701
|
+
logging.level.org.springframework.web=WARN`;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
generateComposerJSON(config) {
|
|
705
|
+
return JSON.stringify({
|
|
706
|
+
name: config.projectName,
|
|
707
|
+
description: config.description || 'PHP backend application',
|
|
708
|
+
type: 'project',
|
|
709
|
+
require: {
|
|
710
|
+
php: '^8.1',
|
|
711
|
+
'laravel/framework': '^10.0'
|
|
712
|
+
},
|
|
713
|
+
requireDev: {
|
|
714
|
+
'phpunit/phpunit': '^10.0'
|
|
715
|
+
},
|
|
716
|
+
autoload: {
|
|
717
|
+
psr4: {
|
|
718
|
+
'App\\\\': 'app/'
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
authors: [
|
|
722
|
+
{
|
|
723
|
+
name: config.author || 'OpenWork Agent'
|
|
724
|
+
}
|
|
725
|
+
],
|
|
726
|
+
minimumStability: 'stable',
|
|
727
|
+
preferStable: true
|
|
728
|
+
}, null, 2);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
generateMainGo(config) {
|
|
732
|
+
return `package main
|
|
733
|
+
|
|
734
|
+
import (
|
|
735
|
+
"log"
|
|
736
|
+
"net/http"
|
|
737
|
+
"github.com/gin-gonic/gin"
|
|
738
|
+
"github.com/gin-contrib/cors"
|
|
739
|
+
"github.com/joho/godotenv"
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
func main() {
|
|
743
|
+
// Load environment variables
|
|
744
|
+
if err := godotenv.Load(); err != nil {
|
|
745
|
+
log.Println("No .env file found")
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Initialize Gin router
|
|
749
|
+
r := gin.Default()
|
|
750
|
+
|
|
751
|
+
// Configure CORS
|
|
752
|
+
r.Use(cors.Default())
|
|
753
|
+
|
|
754
|
+
// Health check endpoint
|
|
755
|
+
r.GET("/health", func(c *gin.Context) {
|
|
756
|
+
c.JSON(http.StatusOK, gin.H{
|
|
757
|
+
"status": "ok",
|
|
758
|
+
"service": "${config.projectName}",
|
|
759
|
+
})
|
|
760
|
+
})
|
|
761
|
+
|
|
762
|
+
// Start server
|
|
763
|
+
log.Println("Server starting on :8080")
|
|
764
|
+
if err := r.Run(":8080"); err != nil {
|
|
765
|
+
log.Fatal("Failed to start server:", err)
|
|
766
|
+
}
|
|
767
|
+
}`;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
generateMainRs(config) {
|
|
771
|
+
return `use actix_web::{get, App, HttpServer, Responder, HttpResponse};
|
|
772
|
+
use std::env;
|
|
773
|
+
|
|
774
|
+
#[get("/health")]
|
|
775
|
+
async fn health() -> impl Responder {
|
|
776
|
+
HttpResponse::Ok().json(serde_json::json!({
|
|
777
|
+
"status": "ok",
|
|
778
|
+
"service": "${config.projectName}"
|
|
779
|
+
}))
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
#[actix_web::main]
|
|
783
|
+
async fn main() -> std::io::Result<()> {
|
|
784
|
+
// Load environment variables
|
|
785
|
+
dotenv::dotenv().ok();
|
|
786
|
+
|
|
787
|
+
let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
|
|
788
|
+
let bind_address = format!("0.0.0.0:{}", port);
|
|
789
|
+
|
|
790
|
+
HttpServer::new(|| {
|
|
791
|
+
App::new()
|
|
792
|
+
.service(health)
|
|
793
|
+
})
|
|
794
|
+
.bind(&bind_address)?
|
|
795
|
+
.run()
|
|
796
|
+
.await
|
|
797
|
+
}`;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Docker generation methods
|
|
801
|
+
generateDockerfileNode(config) {
|
|
802
|
+
return `FROM node:18-alpine
|
|
803
|
+
|
|
804
|
+
WORKDIR /app
|
|
805
|
+
|
|
806
|
+
COPY package*.json ./
|
|
807
|
+
RUN npm ci --only=production
|
|
808
|
+
|
|
809
|
+
COPY . .
|
|
810
|
+
RUN npm run build
|
|
811
|
+
|
|
812
|
+
EXPOSE 3000
|
|
813
|
+
|
|
814
|
+
CMD ["npm", "start"]`;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
generateDockerfilePython(config) {
|
|
818
|
+
return `FROM python:3.11-slim
|
|
819
|
+
|
|
820
|
+
WORKDIR /app
|
|
821
|
+
|
|
822
|
+
COPY requirements.txt .
|
|
823
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
824
|
+
|
|
825
|
+
COPY . .
|
|
826
|
+
|
|
827
|
+
EXPOSE 8000
|
|
828
|
+
|
|
829
|
+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]`;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
generateDockerfileJava(config) {
|
|
833
|
+
return `FROM maven:3.9-openjdk-17
|
|
834
|
+
|
|
835
|
+
WORKDIR /app
|
|
836
|
+
COPY pom.xml .
|
|
837
|
+
RUN mvn dependency:go-offline
|
|
838
|
+
|
|
839
|
+
COPY . .
|
|
840
|
+
RUN mvn clean package -DskipTests
|
|
841
|
+
|
|
842
|
+
EXPOSE 8080
|
|
843
|
+
|
|
844
|
+
CMD ["java", "-jar", "target/${config.projectName}-1.0.0.jar"]`;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
generateDockerfileGo(config) {
|
|
848
|
+
return `FROM golang:1.21-alpine AS builder
|
|
849
|
+
|
|
850
|
+
WORKDIR /app
|
|
851
|
+
COPY go.mod go.sum ./
|
|
852
|
+
RUN go mod download
|
|
853
|
+
|
|
854
|
+
COPY . .
|
|
855
|
+
RUN CGO_ENABLED=0 go build -o main .
|
|
856
|
+
|
|
857
|
+
FROM alpine:latest
|
|
858
|
+
RUN apk --no-cache add ca-certificates
|
|
859
|
+
WORKDIR /app
|
|
860
|
+
COPY --from=builder /app/main .
|
|
861
|
+
|
|
862
|
+
EXPOSE 8080
|
|
863
|
+
|
|
864
|
+
CMD ["./main"]`;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
generateDockerfileRust(config) {
|
|
868
|
+
return `FROM rust:1.73-alpine AS builder
|
|
869
|
+
|
|
870
|
+
WORKDIR /app
|
|
871
|
+
COPY Cargo.toml Cargo.lock ./
|
|
872
|
+
RUN mkdir src && echo "fn main() {}" > src/main.rs
|
|
873
|
+
RUN cargo build --release
|
|
874
|
+
RUN rm -rf src
|
|
875
|
+
|
|
876
|
+
COPY . .
|
|
877
|
+
RUN touch src/main.rs && cargo build --release
|
|
878
|
+
|
|
879
|
+
FROM alpine:latest
|
|
880
|
+
RUN apk --no-cache add ca-certificates
|
|
881
|
+
WORKDIR /app
|
|
882
|
+
COPY --from=builder /app/target/release/${config.projectName} .
|
|
883
|
+
|
|
884
|
+
EXPOSE 8080
|
|
885
|
+
|
|
886
|
+
CMD ["./${config.projectName}"]`;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
generateDockerfilePhp(config) {
|
|
890
|
+
return `FROM php:8.1-fpm-alpine
|
|
891
|
+
|
|
892
|
+
WORKDIR /app
|
|
893
|
+
|
|
894
|
+
RUN docker-php-ext-install pdo pdo_mysql
|
|
895
|
+
|
|
896
|
+
COPY . .
|
|
897
|
+
|
|
898
|
+
EXPOSE 9000
|
|
899
|
+
|
|
900
|
+
CMD ["php-fpm"]`;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
generateDockerCompose(config) {
|
|
904
|
+
const dbServices = {
|
|
905
|
+
mongodb: `
|
|
906
|
+
mongodb:
|
|
907
|
+
image: mongo:7.0
|
|
908
|
+
ports:
|
|
909
|
+
- "27017:27017"
|
|
910
|
+
volumes:
|
|
911
|
+
- mongodb_data:/data/db`,
|
|
912
|
+
postgresql: `
|
|
913
|
+
postgres:
|
|
914
|
+
image: postgres:15
|
|
915
|
+
ports:
|
|
916
|
+
- "5432:5432"
|
|
917
|
+
environment:
|
|
918
|
+
POSTGRES_DB: ${config.projectName}
|
|
919
|
+
POSTGRES_USER: postgres
|
|
920
|
+
POSTGRES_PASSWORD: password
|
|
921
|
+
volumes:
|
|
922
|
+
- postgres_data:/var/lib/postgresql/data`,
|
|
923
|
+
mysql: `
|
|
924
|
+
mysql:
|
|
925
|
+
image: mysql:8.0
|
|
926
|
+
ports:
|
|
927
|
+
- "3306:3306"
|
|
928
|
+
environment:
|
|
929
|
+
MYSQL_DATABASE: ${config.projectName}
|
|
930
|
+
MYSQL_USER: user
|
|
931
|
+
MYSQL_PASSWORD: password
|
|
932
|
+
MYSQL_ROOT_PASSWORD: rootpassword
|
|
933
|
+
volumes:
|
|
934
|
+
- mysql_data:/var/lib/mysql`,
|
|
935
|
+
redis: `
|
|
936
|
+
redis:
|
|
937
|
+
image: redis:7.2-alpine
|
|
938
|
+
ports:
|
|
939
|
+
- "6379:6379"
|
|
940
|
+
volumes:
|
|
941
|
+
- redis_data:/data`
|
|
942
|
+
};
|
|
943
|
+
|
|
944
|
+
const dbService = config.database ? dbServices[config.database] : '';
|
|
945
|
+
|
|
946
|
+
return `version: '3.8'
|
|
947
|
+
|
|
948
|
+
services:
|
|
949
|
+
api:
|
|
950
|
+
build: .
|
|
951
|
+
ports:
|
|
952
|
+
- "3000:3000"
|
|
953
|
+
depends_on:
|
|
954
|
+
${config.database ? ` - ${config.database}` : ''}
|
|
955
|
+
environment:
|
|
956
|
+
- DATABASE_URL=${config.database ? `${config.database}://localhost:27017/${config.projectName}` : ''}
|
|
957
|
+
- NODE_ENV=development
|
|
958
|
+
volumes:
|
|
959
|
+
- .:/app
|
|
960
|
+
- /app/node_modules
|
|
961
|
+
${dbService}
|
|
962
|
+
|
|
963
|
+
volumes:
|
|
964
|
+
${config.database ? ` ${config.database}_data:` : ''}`;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
generateDockerignore(config) {
|
|
968
|
+
return `node_modules
|
|
969
|
+
npm-debug.log
|
|
970
|
+
dist
|
|
971
|
+
.env
|
|
972
|
+
.env.local
|
|
973
|
+
.env.development.local
|
|
974
|
+
.env.test.local
|
|
975
|
+
.env.production.local
|
|
976
|
+
coverage
|
|
977
|
+
.nyc_output
|
|
978
|
+
.DS_Store
|
|
979
|
+
Thumbs.db`;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
async generateNodeConfig(configPath, config) {
|
|
983
|
+
const configContent = `
|
|
984
|
+
module.exports = {
|
|
985
|
+
port: process.env.PORT || 3000,
|
|
986
|
+
mongodb: {
|
|
987
|
+
uri: process.env.DATABASE_URL || 'mongodb://localhost:27017/${config.projectName}',
|
|
988
|
+
options: {
|
|
989
|
+
useNewUrlParser: true,
|
|
990
|
+
useUnifiedTopology: true,
|
|
991
|
+
}
|
|
992
|
+
},
|
|
993
|
+
jwt: {
|
|
994
|
+
secret: process.env.JWT_SECRET || 'your-secret-key',
|
|
995
|
+
expiresIn: process.env.JWT_EXPIRES_IN || '7d'
|
|
996
|
+
},
|
|
997
|
+
cors: {
|
|
998
|
+
origin: process.env.CORS_ORIGINS ? process.env.CORS_ORIGINS.split(',') : ['http://localhost:3000'],
|
|
999
|
+
credentials: true
|
|
1000
|
+
},
|
|
1001
|
+
logging: {
|
|
1002
|
+
level: process.env.LOG_LEVEL || 'info'
|
|
1003
|
+
}
|
|
1004
|
+
};`;
|
|
1005
|
+
|
|
1006
|
+
await fs.writeFile(path.join(configPath, 'index.js'), configContent);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
async generatePythonConfig(configPath, config) {
|
|
1010
|
+
const configContent = `
|
|
1011
|
+
import os
|
|
1012
|
+
from typing import List
|
|
1013
|
+
|
|
1014
|
+
class Config:
|
|
1015
|
+
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
|
|
1016
|
+
DATABASE_URL = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
|
|
1017
|
+
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
1018
|
+
CORS_ORIGINS = os.environ.get('CORS_ORIGINS', 'http://localhost:3000').split(',')
|
|
1019
|
+
`;
|
|
1020
|
+
|
|
1021
|
+
await fs.writeFile(path.join(configPath, '__init__.py'), configContent);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
async generateJavaConfig(projectPath, config) {
|
|
1025
|
+
// Spring Boot config is already in application.properties
|
|
1026
|
+
const configDir = path.join(projectPath, 'src/main/java/com/openwork/config');
|
|
1027
|
+
await fs.ensureDir(configDir);
|
|
1028
|
+
|
|
1029
|
+
const configContent = `package com.openwork.config;
|
|
1030
|
+
|
|
1031
|
+
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
1032
|
+
import org.springframework.stereotype.Component;
|
|
1033
|
+
|
|
1034
|
+
@Component
|
|
1035
|
+
@ConfigurationProperties(prefix = "app")
|
|
1036
|
+
public class AppConfig {
|
|
1037
|
+
private String name = "${config.projectName}";
|
|
1038
|
+
private String version = "1.0.0";
|
|
1039
|
+
|
|
1040
|
+
// getters and setters
|
|
1041
|
+
public String getName() { return name; }
|
|
1042
|
+
public void setName(String name) { this.name = name; }
|
|
1043
|
+
|
|
1044
|
+
public String getVersion() { return version; }
|
|
1045
|
+
public void setVersion(String version) { this.version = version; }
|
|
1046
|
+
}`;
|
|
1047
|
+
|
|
1048
|
+
await fs.writeFile(path.join(configDir, 'AppConfig.java'), configContent);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
async generateGoConfig(projectPath, config) {
|
|
1052
|
+
const configDir = path.join(projectPath, 'config');
|
|
1053
|
+
await fs.ensureDir(configDir);
|
|
1054
|
+
|
|
1055
|
+
const configContent = `package config
|
|
1056
|
+
|
|
1057
|
+
import (
|
|
1058
|
+
"os"
|
|
1059
|
+
"fmt"
|
|
1060
|
+
)
|
|
1061
|
+
|
|
1062
|
+
type Config struct {
|
|
1063
|
+
Port string
|
|
1064
|
+
DatabaseURL string
|
|
1065
|
+
JWTSecret string
|
|
1066
|
+
CORSOrigins []string
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
func LoadConfig() *Config {
|
|
1070
|
+
return &Config{
|
|
1071
|
+
Port: getEnv("PORT", "8080"),
|
|
1072
|
+
DatabaseURL: getEnv("DATABASE_URL", "postgres://user:password@localhost/${config.projectName}?sslmode=disable"),
|
|
1073
|
+
JWTSecret: getEnv("JWT_SECRET", "your-secret-key"),
|
|
1074
|
+
CORSOrigins: []string{getEnv("CORS_ORIGINS", "http://localhost:3000")},
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
func getEnv(key, defaultValue string) string {
|
|
1079
|
+
if value := os.Getenv(key); value != "" {
|
|
1080
|
+
return value
|
|
1081
|
+
}
|
|
1082
|
+
return defaultValue
|
|
1083
|
+
}`;
|
|
1084
|
+
|
|
1085
|
+
await fs.writeFile(path.join(configDir, 'config.go'), configContent);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
async generateRustConfig(projectPath, config) {
|
|
1089
|
+
const configDir = path.join(projectPath, 'src/config');
|
|
1090
|
+
await fs.ensureDir(configDir);
|
|
1091
|
+
|
|
1092
|
+
const configContent = `use std::env;
|
|
1093
|
+
|
|
1094
|
+
pub struct Config {
|
|
1095
|
+
pub port: u16,
|
|
1096
|
+
pub database_url: String,
|
|
1097
|
+
pub jwt_secret: String,
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
impl Config {
|
|
1101
|
+
pub fn from_env() -> Self {
|
|
1102
|
+
Config {
|
|
1103
|
+
port: env::var("PORT")
|
|
1104
|
+
.unwrap_or_else(|_| "8080".to_string())
|
|
1105
|
+
.parse()
|
|
1106
|
+
.unwrap_or(8080),
|
|
1107
|
+
database_url: env::var("DATABASE_URL")
|
|
1108
|
+
.unwrap_or_else(|_| format!("sqlite://{}", "${config.projectName}")),
|
|
1109
|
+
jwt_secret: env::var("JWT_SECRET")
|
|
1110
|
+
.unwrap_or_else(|_| "your-secret-key".to_string()),
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}`;
|
|
1114
|
+
|
|
1115
|
+
await fs.writeFile(path.join(configDir, 'mod.rs'), configContent);
|
|
1116
|
+
await fs.writeFile(path.join(configDir, 'lib.rs'), configContent);
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
async generatePhpConfig(projectPath, config) {
|
|
1120
|
+
const configDir = path.join(projectPath, 'config');
|
|
1121
|
+
await fs.ensureDir(configDir);
|
|
1122
|
+
|
|
1123
|
+
const configContent = `<?php
|
|
1124
|
+
|
|
1125
|
+
return [
|
|
1126
|
+
'name' => env('APP_NAME', '${config.projectName}'),
|
|
1127
|
+
'env' => env('APP_ENV', 'development'),
|
|
1128
|
+
'debug' => (bool) env('APP_DEBUG', true),
|
|
1129
|
+
'url' => env('APP_URL', 'http://localhost'),
|
|
1130
|
+
|
|
1131
|
+
'database' => [
|
|
1132
|
+
'driver' => env('DB_CONNECTION', 'mysql'),
|
|
1133
|
+
'host' => env('DB_HOST', '127.0.0.1'),
|
|
1134
|
+
'port' => env('DB_PORT', '3306'),
|
|
1135
|
+
'database' => env('DB_DATABASE', '${config.projectName}'),
|
|
1136
|
+
'username' => env('DB_USERNAME', 'root'),
|
|
1137
|
+
'password' => env('DB_PASSWORD', ''),
|
|
1138
|
+
],
|
|
1139
|
+
|
|
1140
|
+
'cors' => [
|
|
1141
|
+
'paths' => ['api/*'],
|
|
1142
|
+
'allowed_methods' => ['*'],
|
|
1143
|
+
'allowed_origins' => ['*'],
|
|
1144
|
+
'allowed_headers' => ['*'],
|
|
1145
|
+
],
|
|
1146
|
+
];`;
|
|
1147
|
+
|
|
1148
|
+
await fs.writeFile(path.join(configDir, 'app.php'), configContent);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
async generateCIFiles(projectPath, config) {
|
|
1152
|
+
const githubDir = path.join(projectPath, '.github/workflows');
|
|
1153
|
+
await fs.ensureDir(githubDir);
|
|
1154
|
+
|
|
1155
|
+
const ciContent = `name: CI/CD Pipeline
|
|
1156
|
+
|
|
1157
|
+
on:
|
|
1158
|
+
push:
|
|
1159
|
+
branches: [ main, develop ]
|
|
1160
|
+
pull_request:
|
|
1161
|
+
branches: [ main ]
|
|
1162
|
+
|
|
1163
|
+
jobs:
|
|
1164
|
+
test:
|
|
1165
|
+
runs-on: ubuntu-latest
|
|
1166
|
+
|
|
1167
|
+
services:
|
|
1168
|
+
${config.database ? this.getDatabaseService(config.database) : ''}
|
|
1169
|
+
|
|
1170
|
+
steps:
|
|
1171
|
+
- uses: actions/checkout@v3
|
|
1172
|
+
|
|
1173
|
+
- name: Setup Node.js
|
|
1174
|
+
uses: actions/setup-node@v3
|
|
1175
|
+
with:
|
|
1176
|
+
node-version: '18'
|
|
1177
|
+
cache: 'npm'
|
|
1178
|
+
|
|
1179
|
+
- name: Install dependencies
|
|
1180
|
+
run: npm ci
|
|
1181
|
+
|
|
1182
|
+
- name: Run tests
|
|
1183
|
+
run: npm test
|
|
1184
|
+
|
|
1185
|
+
- name: Build
|
|
1186
|
+
run: npm run build
|
|
1187
|
+
|
|
1188
|
+
deploy:
|
|
1189
|
+
needs: test
|
|
1190
|
+
runs-on: ubuntu-latest
|
|
1191
|
+
if: github.ref == 'refs/heads/main'
|
|
1192
|
+
|
|
1193
|
+
steps:
|
|
1194
|
+
- name: Deploy to production
|
|
1195
|
+
run: echo "Deploy step would go here"`;
|
|
1196
|
+
|
|
1197
|
+
await fs.writeFile(path.join(githubDir, 'ci.yml'), ciContent);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
getDatabaseService(database) {
|
|
1201
|
+
const services = {
|
|
1202
|
+
mongodb: `mongodb:
|
|
1203
|
+
image: mongo:7.0
|
|
1204
|
+
ports:
|
|
1205
|
+
- 27017:27017
|
|
1206
|
+
options: >-
|
|
1207
|
+
--health-cmd "mongosh --eval 'db.runCommand({ping: 1})'"
|
|
1208
|
+
--health-interval 10s
|
|
1209
|
+
--health-timeout 5s
|
|
1210
|
+
--health-retries 5`,
|
|
1211
|
+
postgresql: `postgres:
|
|
1212
|
+
image: postgres:15
|
|
1213
|
+
env:
|
|
1214
|
+
POSTGRES_PASSWORD: postgres
|
|
1215
|
+
POSTGRES_DB: test
|
|
1216
|
+
options: >-
|
|
1217
|
+
--health-cmd pg_isready
|
|
1218
|
+
--health-interval 10s
|
|
1219
|
+
--health-timeout 5s
|
|
1220
|
+
--health-retries 5
|
|
1221
|
+
ports:
|
|
1222
|
+
- 5432:5432`,
|
|
1223
|
+
mysql: `mysql:
|
|
1224
|
+
image: mysql:8.0
|
|
1225
|
+
env:
|
|
1226
|
+
MYSQL_ROOT_PASSWORD: password
|
|
1227
|
+
MYSQL_DATABASE: test
|
|
1228
|
+
options: >-
|
|
1229
|
+
--health-cmd "mysqladmin ping"
|
|
1230
|
+
--health-interval 10s
|
|
1231
|
+
--health-timeout 5s
|
|
1232
|
+
--health-retries 5
|
|
1233
|
+
ports:
|
|
1234
|
+
- 3306:3306`
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
return services[database] || '';
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
module.exports = ProjectGenerator;
|