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,130 @@
|
|
|
1
|
+
use actix_web::{web, HttpResponse, Result};
|
|
2
|
+
use diesel::prelude::*;
|
|
3
|
+
use uuid::Uuid;
|
|
4
|
+
use chrono::Utc;
|
|
5
|
+
|
|
6
|
+
use crate::models::{User, NewUser, UpdateUser, ApiResponse, CreateUserRequest, UpdateUserRequest};
|
|
7
|
+
use crate::schema::users;
|
|
8
|
+
use crate::DbPool;
|
|
9
|
+
|
|
10
|
+
pub async fn get_users(pool: web::Data<DbPool>) -> Result<HttpResponse> {
|
|
11
|
+
let mut conn = pool.get().expect("Failed to get connection");
|
|
12
|
+
|
|
13
|
+
let users = web::block(move || {
|
|
14
|
+
users::table
|
|
15
|
+
.select(User::as_select())
|
|
16
|
+
.load::<User>(&mut conn)
|
|
17
|
+
})
|
|
18
|
+
.await
|
|
19
|
+
.expect("Failed to execute query");
|
|
20
|
+
|
|
21
|
+
Ok(HttpResponse::Ok().json(ApiResponse::success(users)))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pub async fn get_user(
|
|
25
|
+
path: web::Path<Uuid>,
|
|
26
|
+
pool: web::Data<DbPool>
|
|
27
|
+
) -> Result<HttpResponse> {
|
|
28
|
+
let user_id = path.into_inner();
|
|
29
|
+
let mut conn = pool.get().expect("Failed to get connection");
|
|
30
|
+
|
|
31
|
+
let user = web::block(move || {
|
|
32
|
+
users::table
|
|
33
|
+
.filter(users::id.eq(user_id))
|
|
34
|
+
.select(User::as_select())
|
|
35
|
+
.first::<User>(&mut conn)
|
|
36
|
+
.optional()
|
|
37
|
+
})
|
|
38
|
+
.await
|
|
39
|
+
.expect("Failed to execute query");
|
|
40
|
+
|
|
41
|
+
match user {
|
|
42
|
+
Some(user) => Ok(HttpResponse::Ok().json(ApiResponse::success(user))),
|
|
43
|
+
None => Ok(HttpResponse::NotFound().json(ApiResponse::<User>::error(
|
|
44
|
+
"User not found".to_string()
|
|
45
|
+
))),
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub async fn create_user(
|
|
50
|
+
user_data: web::Json<CreateUserRequest>,
|
|
51
|
+
pool: web::Data<DbPool>
|
|
52
|
+
) -> Result<HttpResponse> {
|
|
53
|
+
let new_user = NewUser {
|
|
54
|
+
name: user_data.name.clone(),
|
|
55
|
+
email: user_data.email.clone(),
|
|
56
|
+
age: user_data.age,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
let mut conn = pool.get().expect("Failed to get connection");
|
|
60
|
+
|
|
61
|
+
let user = web::block(move || {
|
|
62
|
+
diesel::insert_into(users::table)
|
|
63
|
+
.values(&new_user)
|
|
64
|
+
.returning(User::as_returning())
|
|
65
|
+
.get_result::<User>(&mut conn)
|
|
66
|
+
})
|
|
67
|
+
.await
|
|
68
|
+
.expect("Failed to execute query");
|
|
69
|
+
|
|
70
|
+
Ok(HttpResponse::Created().json(ApiResponse::success(user)))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
pub async fn update_user(
|
|
74
|
+
path: web::Path<Uuid>,
|
|
75
|
+
user_data: web::Json<UpdateUserRequest>,
|
|
76
|
+
pool: web::Data<DbPool>
|
|
77
|
+
) -> Result<HttpResponse> {
|
|
78
|
+
let user_id = path.into_inner();
|
|
79
|
+
let update_data = UpdateUser {
|
|
80
|
+
name: user_data.name.clone(),
|
|
81
|
+
email: user_data.email.clone(),
|
|
82
|
+
age: user_data.age,
|
|
83
|
+
updated_at: Utc::now(),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
let mut conn = pool.get().expect("Failed to get connection");
|
|
87
|
+
|
|
88
|
+
let user = web::block(move || {
|
|
89
|
+
diesel::update(users::table.filter(users::id.eq(user_id)))
|
|
90
|
+
.set(&update_data)
|
|
91
|
+
.returning(User::as_returning())
|
|
92
|
+
.get_result::<User>(&mut conn)
|
|
93
|
+
.optional()
|
|
94
|
+
})
|
|
95
|
+
.await
|
|
96
|
+
.expect("Failed to execute query");
|
|
97
|
+
|
|
98
|
+
match user {
|
|
99
|
+
Some(user) => Ok(HttpResponse::Ok().json(ApiResponse::success(user))),
|
|
100
|
+
None => Ok(HttpResponse::NotFound().json(ApiResponse::<User>::error(
|
|
101
|
+
"User not found".to_string()
|
|
102
|
+
))),
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
pub async fn delete_user(
|
|
107
|
+
path: web::Path<Uuid>,
|
|
108
|
+
pool: web::Data<DbPool>
|
|
109
|
+
) -> Result<HttpResponse> {
|
|
110
|
+
let user_id = path.into_inner();
|
|
111
|
+
let mut conn = pool.get().expect("Failed to get connection");
|
|
112
|
+
|
|
113
|
+
let rows_affected = web::block(move || {
|
|
114
|
+
diesel::delete(users::table.filter(users::id.eq(user_id)))
|
|
115
|
+
.execute(&mut conn)
|
|
116
|
+
})
|
|
117
|
+
.await
|
|
118
|
+
.expect("Failed to execute query");
|
|
119
|
+
|
|
120
|
+
if rows_affected > 0 {
|
|
121
|
+
Ok(HttpResponse::Ok().json(ApiResponse::<()>::success_with_message(
|
|
122
|
+
(),
|
|
123
|
+
"User deleted successfully".to_string()
|
|
124
|
+
)))
|
|
125
|
+
} else {
|
|
126
|
+
Ok(HttpResponse::NotFound().json(ApiResponse::<()>::error(
|
|
127
|
+
"User not found".to_string()
|
|
128
|
+
)))
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
use actix_web::{web, Scope};
|
|
2
|
+
use uuid::Uuid;
|
|
3
|
+
|
|
4
|
+
use super::user;
|
|
5
|
+
|
|
6
|
+
pub fn config(cfg: &mut web::ServiceConfig) {
|
|
7
|
+
cfg.service(
|
|
8
|
+
web::scope("/users")
|
|
9
|
+
.route("", web::get().to(user::get_users))
|
|
10
|
+
.route("/{id}", web::get().to(user::get_user))
|
|
11
|
+
.route("", web::post().to(user::create_user))
|
|
12
|
+
.route("/{id}", web::put().to(user::update_user))
|
|
13
|
+
.route("/{id}", web::delete().to(user::delete_user))
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
use actix_web::{web, App, HttpServer, middleware::Logger};
|
|
2
|
+
use actix_cors::Cors;
|
|
3
|
+
use diesel::prelude::*;
|
|
4
|
+
use diesel::r2d2::{self, ConnectionManager};
|
|
5
|
+
use std::env;
|
|
6
|
+
|
|
7
|
+
mod config;
|
|
8
|
+
mod models;
|
|
9
|
+
mod schema;
|
|
10
|
+
mod handlers;
|
|
11
|
+
mod services;
|
|
12
|
+
|
|
13
|
+
use config::database::establish_connection;
|
|
14
|
+
use handlers::user_routes;
|
|
15
|
+
|
|
16
|
+
#[actix_web::main]
|
|
17
|
+
async fn main() -> std::io::Result<()> {
|
|
18
|
+
env_logger::init();
|
|
19
|
+
dotenv::dotenv().ok();
|
|
20
|
+
|
|
21
|
+
// Database connection
|
|
22
|
+
let conn_spec = establish_connection();
|
|
23
|
+
|
|
24
|
+
println!("🚀 {{pascalCase projectName}} server starting on 0.0.0.0:8080");
|
|
25
|
+
|
|
26
|
+
HttpServer::new(move || {
|
|
27
|
+
let cors = Cors::default()
|
|
28
|
+
.allow_any_origin()
|
|
29
|
+
.allow_any_method()
|
|
30
|
+
.allow_any_header()
|
|
31
|
+
.max_age(3600);
|
|
32
|
+
|
|
33
|
+
App::new()
|
|
34
|
+
.app_data(web::Data::new(conn_spec.clone()))
|
|
35
|
+
.wrap(cors)
|
|
36
|
+
.wrap(Logger::default())
|
|
37
|
+
.service(
|
|
38
|
+
web::scope("/api")
|
|
39
|
+
.configure(user_routes::config)
|
|
40
|
+
)
|
|
41
|
+
.route("/health", web::get().to(health_check))
|
|
42
|
+
})
|
|
43
|
+
.bind("0.0.0.0:8080")?
|
|
44
|
+
.run()
|
|
45
|
+
.await
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async fn health_check() -> impl actix_web::Responder {
|
|
49
|
+
actix_web::HttpResponse::Ok().json(serde_json::json!({
|
|
50
|
+
"status": "OK",
|
|
51
|
+
"timestamp": "2024-01-01T00:00:00Z"
|
|
52
|
+
}))
|
|
53
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
use serde::{Deserialize, Serialize};
|
|
2
|
+
use chrono::{DateTime, Utc};
|
|
3
|
+
use uuid::Uuid;
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Clone, Queryable, Selectable, Serialize)]
|
|
6
|
+
#[diesel(table_name = crate::schema::users)]
|
|
7
|
+
#[diesel(check_for_backend(diesel::pg::Pg))]
|
|
8
|
+
pub struct User {
|
|
9
|
+
pub id: Uuid,
|
|
10
|
+
pub name: String,
|
|
11
|
+
pub email: String,
|
|
12
|
+
pub age: Option<i32>,
|
|
13
|
+
pub created_at: DateTime<Utc>,
|
|
14
|
+
pub updated_at: DateTime<Utc>,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[derive(Debug, Insertable, Serialize, Deserialize)]
|
|
18
|
+
#[diesel(table_name = crate::schema::users)]
|
|
19
|
+
pub struct NewUser {
|
|
20
|
+
pub name: String,
|
|
21
|
+
pub email: String,
|
|
22
|
+
pub age: Option<i32>,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Debug, AsChangeset, Deserialize)]
|
|
26
|
+
#[diesel(table_name = crate::schema::users)]
|
|
27
|
+
pub struct UpdateUser {
|
|
28
|
+
pub name: Option<String>,
|
|
29
|
+
pub email: Option<String>,
|
|
30
|
+
pub age: Option<i32>,
|
|
31
|
+
pub updated_at: DateTime<Utc>,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#[derive(Debug, Serialize, Deserialize)]
|
|
35
|
+
pub struct ApiResponse<T> {
|
|
36
|
+
pub success: bool,
|
|
37
|
+
pub data: Option<T>,
|
|
38
|
+
pub message: Option<String>,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
impl<T> ApiResponse<T> {
|
|
42
|
+
pub fn success(data: T) -> Self {
|
|
43
|
+
Self {
|
|
44
|
+
success: true,
|
|
45
|
+
data: Some(data),
|
|
46
|
+
message: None,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
pub fn success_with_message(data: T, message: String) -> Self {
|
|
51
|
+
Self {
|
|
52
|
+
success: true,
|
|
53
|
+
data: Some(data),
|
|
54
|
+
message: Some(message),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
pub fn error(message: String) -> Self {
|
|
59
|
+
Self {
|
|
60
|
+
success: false,
|
|
61
|
+
data: None,
|
|
62
|
+
message: Some(message),
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#[derive(Debug, Serialize, Deserialize)]
|
|
68
|
+
pub struct CreateUserRequest {
|
|
69
|
+
pub name: String,
|
|
70
|
+
pub email: String,
|
|
71
|
+
pub age: Option<i32>,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#[derive(Debug, Serialize, Deserialize)]
|
|
75
|
+
pub struct UpdateUserRequest {
|
|
76
|
+
pub name: Option<String>,
|
|
77
|
+
pub email: Option<String>,
|
|
78
|
+
pub age: Option<i32>,
|
|
79
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const Handlebars = require('handlebars');
|
|
4
|
+
|
|
5
|
+
class FileManager {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.registerHandlebarsHelpers();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
registerHandlebarsHelpers() {
|
|
11
|
+
Handlebars.registerHelper('camelCase', (str) => {
|
|
12
|
+
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
|
|
13
|
+
return index === 0 ? word.toLowerCase() : word.toUpperCase();
|
|
14
|
+
}).replace(/\s+/g, '');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
Handlebars.registerHelper('pascalCase', (str) => {
|
|
18
|
+
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => {
|
|
19
|
+
return word.toUpperCase();
|
|
20
|
+
}).replace(/\s+/g, '');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
Handlebars.registerHelper('kebabCase', (str) => {
|
|
24
|
+
return str.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
Handlebars.registerHelper('snakeCase', (str) => {
|
|
28
|
+
return str.replace(/([a-z])([A-Z])/g, '$1_$2').replace(/\s+/g, '_').toLowerCase();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
Handlebars.registerHelper('upperCase', (str) => {
|
|
32
|
+
return str.toUpperCase();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
Handlebars.registerHelper('lowerCase', (str) => {
|
|
36
|
+
return str.toLowerCase();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Common conditional helpers
|
|
40
|
+
Handlebars.registerHelper('eq', (a, b) => {
|
|
41
|
+
return a === b;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
Handlebars.registerHelper('ne', (a, b) => {
|
|
45
|
+
return a !== b;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
Handlebars.registerHelper('gt', (a, b) => {
|
|
49
|
+
return a > b;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
Handlebars.registerHelper('lt', (a, b) => {
|
|
53
|
+
return a < b;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
Handlebars.registerHelper('and', (...args) => {
|
|
57
|
+
return args.slice(0, -1).every(Boolean);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
Handlebars.registerHelper('or', (...args) => {
|
|
61
|
+
return args.slice(0, -1).some(Boolean);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
Handlebars.registerHelper('not', (value) => {
|
|
65
|
+
return !value;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async copyDirectory(src, dest, config = {}) {
|
|
70
|
+
const items = await fs.readdir(src);
|
|
71
|
+
|
|
72
|
+
for (const item of items) {
|
|
73
|
+
const srcPath = path.join(src, item);
|
|
74
|
+
const destPath = path.join(dest, item);
|
|
75
|
+
const stat = await fs.stat(srcPath);
|
|
76
|
+
|
|
77
|
+
if (stat.isDirectory()) {
|
|
78
|
+
await fs.ensureDir(destPath);
|
|
79
|
+
await this.copyDirectory(srcPath, destPath, config);
|
|
80
|
+
} else {
|
|
81
|
+
if (this.shouldProcessFile(item)) {
|
|
82
|
+
await this.processTemplate(srcPath, destPath, config);
|
|
83
|
+
} else {
|
|
84
|
+
await fs.copy(srcPath, destPath);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
shouldProcessFile(filename) {
|
|
91
|
+
const processableExtensions = ['.hbs', '.handlebars', '.txt', '.js', '.ts', '.py', '.java', '.go', '.rs', '.php', '.html', '.md'];
|
|
92
|
+
return processableExtensions.some(ext => filename.endsWith(ext));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async processTemplate(srcPath, destPath, config) {
|
|
96
|
+
try {
|
|
97
|
+
const content = await fs.readFile(srcPath, 'utf8');
|
|
98
|
+
const template = Handlebars.compile(content);
|
|
99
|
+
const processed = template(config);
|
|
100
|
+
|
|
101
|
+
// Remove .hbs extension if present
|
|
102
|
+
const finalDestPath = destPath.endsWith('.hbs') ? destPath.slice(0, -4) : destPath;
|
|
103
|
+
|
|
104
|
+
await fs.writeFile(finalDestPath, processed);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
// If template processing fails, copy the file as-is
|
|
107
|
+
await fs.copy(srcPath, destPath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async writeFileWithTemplate(templatePath, destPath, config) {
|
|
112
|
+
if (await fs.pathExists(templatePath)) {
|
|
113
|
+
await this.processTemplate(templatePath, destPath, config);
|
|
114
|
+
} else {
|
|
115
|
+
throw new Error(`Template file not found: ${templatePath}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async ensureDir(dirPath) {
|
|
120
|
+
await fs.ensureDir(dirPath);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async copyFile(src, dest) {
|
|
124
|
+
await fs.copy(src, dest);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async writeFile(filePath, content) {
|
|
128
|
+
await fs.writeFile(filePath, content);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async readFile(filePath) {
|
|
132
|
+
return await fs.readFile(filePath, 'utf8');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async pathExists(filePath) {
|
|
136
|
+
return await fs.pathExists(filePath);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async readdir(dirPath) {
|
|
140
|
+
return await fs.readdir(dirPath);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async stat(filePath) {
|
|
144
|
+
return await fs.stat(filePath);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
createDirectoryStructure(basePath, structure) {
|
|
148
|
+
return Promise.all(
|
|
149
|
+
Object.entries(structure).map(async ([path, content]) => {
|
|
150
|
+
const fullPath = this.resolvePath(basePath, path);
|
|
151
|
+
|
|
152
|
+
if (typeof content === 'object' && !Array.isArray(content)) {
|
|
153
|
+
await fs.ensureDir(fullPath);
|
|
154
|
+
return this.createDirectoryStructure(fullPath, content);
|
|
155
|
+
} else if (Array.isArray(content)) {
|
|
156
|
+
await fs.ensureDir(fullPath);
|
|
157
|
+
return Promise.all(
|
|
158
|
+
content.map(item => this.createDirectoryStructure(fullPath, item))
|
|
159
|
+
);
|
|
160
|
+
} else {
|
|
161
|
+
await fs.ensureDir(path.dirname(fullPath));
|
|
162
|
+
return fs.writeFile(fullPath, content || '');
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
resolvePath(base, relativePath) {
|
|
169
|
+
return path.resolve(base, relativePath);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getFileExtension(filename) {
|
|
173
|
+
return path.extname(filename);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getFileName(filename) {
|
|
177
|
+
return path.basename(filename, path.extname(filename));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
formatTemplate(template, data) {
|
|
181
|
+
const compiled = Handlebars.compile(template);
|
|
182
|
+
return compiled(data);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = FileManager;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// Common template files
|
|
2
|
+
exports.generateGitignore = function(config) {
|
|
3
|
+
const gitignoreContent = `
|
|
4
|
+
# Dependencies
|
|
5
|
+
node_modules/
|
|
6
|
+
__pycache__/
|
|
7
|
+
target/
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
vendor/
|
|
11
|
+
|
|
12
|
+
# Environment variables
|
|
13
|
+
.env
|
|
14
|
+
.env.local
|
|
15
|
+
.env.development.local
|
|
16
|
+
.env.test.local
|
|
17
|
+
.env.production.local
|
|
18
|
+
|
|
19
|
+
# Logs
|
|
20
|
+
logs
|
|
21
|
+
*.log
|
|
22
|
+
npm-debug.log*
|
|
23
|
+
yarn-debug.log*
|
|
24
|
+
yarn-error.log*
|
|
25
|
+
lerna-debug.log*
|
|
26
|
+
|
|
27
|
+
# Runtime data
|
|
28
|
+
pids
|
|
29
|
+
*.pid
|
|
30
|
+
*.seed
|
|
31
|
+
*.pid.lock
|
|
32
|
+
|
|
33
|
+
# Coverage directory used by tools like istanbul
|
|
34
|
+
coverage/
|
|
35
|
+
*.lcov
|
|
36
|
+
|
|
37
|
+
# nyc test coverage
|
|
38
|
+
.nyc_output
|
|
39
|
+
|
|
40
|
+
# Dependency directories
|
|
41
|
+
node_modules/
|
|
42
|
+
jspm_packages/
|
|
43
|
+
|
|
44
|
+
# Optional npm cache directory
|
|
45
|
+
.npm
|
|
46
|
+
|
|
47
|
+
# Optional eslint cache
|
|
48
|
+
.eslintcache
|
|
49
|
+
|
|
50
|
+
# Optional REPL history
|
|
51
|
+
.node_repl_history
|
|
52
|
+
|
|
53
|
+
# Output of 'npm pack'
|
|
54
|
+
*.tgz
|
|
55
|
+
|
|
56
|
+
# Yarn Integrity file
|
|
57
|
+
.yarn-integrity
|
|
58
|
+
|
|
59
|
+
# dotenv environment variables file
|
|
60
|
+
.env
|
|
61
|
+
.env.test
|
|
62
|
+
|
|
63
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
64
|
+
.cache
|
|
65
|
+
.parcel-cache
|
|
66
|
+
|
|
67
|
+
# next.js build output
|
|
68
|
+
.next
|
|
69
|
+
|
|
70
|
+
# nuxt.js build output
|
|
71
|
+
.nuxt
|
|
72
|
+
|
|
73
|
+
# vuepress build output
|
|
74
|
+
.vuepress/dist
|
|
75
|
+
|
|
76
|
+
# Serverless directories
|
|
77
|
+
.serverless/
|
|
78
|
+
|
|
79
|
+
# FuseBox cache
|
|
80
|
+
.fusebox/
|
|
81
|
+
|
|
82
|
+
# DynamoDB Local files
|
|
83
|
+
.dynamodb/
|
|
84
|
+
|
|
85
|
+
# TernJS port file
|
|
86
|
+
.tern-port
|
|
87
|
+
|
|
88
|
+
# Stores VSCode versions used for testing VSCode extensions
|
|
89
|
+
.vscode-test
|
|
90
|
+
|
|
91
|
+
# IDE
|
|
92
|
+
.vscode/
|
|
93
|
+
.idea/
|
|
94
|
+
*.swp
|
|
95
|
+
*.swo
|
|
96
|
+
|
|
97
|
+
# OS
|
|
98
|
+
.DS_Store
|
|
99
|
+
Thumbs.db
|
|
100
|
+
|
|
101
|
+
# Database
|
|
102
|
+
*.db
|
|
103
|
+
*.sqlite
|
|
104
|
+
*.sqlite3
|
|
105
|
+
|
|
106
|
+
# Docker
|
|
107
|
+
.dockerignore
|
|
108
|
+
|
|
109
|
+
# Go
|
|
110
|
+
*.exe
|
|
111
|
+
*.exe~
|
|
112
|
+
*.dll
|
|
113
|
+
*.so
|
|
114
|
+
*.dylib
|
|
115
|
+
*.test
|
|
116
|
+
*.out
|
|
117
|
+
|
|
118
|
+
# Rust
|
|
119
|
+
/target/
|
|
120
|
+
**/*.rs.bk
|
|
121
|
+
Cargo.lock
|
|
122
|
+
|
|
123
|
+
# Python
|
|
124
|
+
__pycache__/
|
|
125
|
+
*.py[cod]
|
|
126
|
+
*$py.class
|
|
127
|
+
*.so
|
|
128
|
+
.Python
|
|
129
|
+
env/
|
|
130
|
+
venv/
|
|
131
|
+
ENV/
|
|
132
|
+
env.bak/
|
|
133
|
+
venv.bak/
|
|
134
|
+
.idea/
|
|
135
|
+
.vscode/
|
|
136
|
+
|
|
137
|
+
# Java
|
|
138
|
+
*.class
|
|
139
|
+
*.log
|
|
140
|
+
*.jar
|
|
141
|
+
*.war
|
|
142
|
+
*.ear
|
|
143
|
+
*.zip
|
|
144
|
+
*.tar.gz
|
|
145
|
+
*.rar
|
|
146
|
+
|
|
147
|
+
# IDE files
|
|
148
|
+
.metadata/
|
|
149
|
+
.recommenders/
|
|
150
|
+
.settings/
|
|
151
|
+
.loadpath
|
|
152
|
+
.factorypath
|
|
153
|
+
.project
|
|
154
|
+
.classpath
|
|
155
|
+
.c9/
|
|
156
|
+
.launch/
|
|
157
|
+
.settings/
|
|
158
|
+
.springBeans
|
|
159
|
+
.sts4-cache/
|
|
160
|
+
|
|
161
|
+
# Temporary files
|
|
162
|
+
*.tmp
|
|
163
|
+
*.temp
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
return gitignoreContent;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
exports.generateEnvExample = function(config) {
|
|
170
|
+
const commonEnv = `# Server Configuration
|
|
171
|
+
PORT=3000
|
|
172
|
+
NODE_ENV=development
|
|
173
|
+
|
|
174
|
+
# Database Configuration
|
|
175
|
+
DATABASE_URL=mongodb://localhost:27017/${config.projectName}
|
|
176
|
+
DB_NAME=${config.projectName}
|
|
177
|
+
|
|
178
|
+
# JWT Configuration
|
|
179
|
+
JWT_SECRET=your-super-secret-jwt-key
|
|
180
|
+
JWT_EXPIRES_IN=7d
|
|
181
|
+
|
|
182
|
+
# CORS Configuration
|
|
183
|
+
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001
|
|
184
|
+
|
|
185
|
+
# Logging
|
|
186
|
+
LOG_LEVEL=info
|
|
187
|
+
|
|
188
|
+
# External Services
|
|
189
|
+
REDIS_URL=redis://localhost:6379
|
|
190
|
+
SMTP_HOST=smtp.gmail.com
|
|
191
|
+
SMTP_PORT=587
|
|
192
|
+
SMTP_USER=your-email@gmail.com
|
|
193
|
+
SMTP_PASS=your-app-password
|
|
194
|
+
|
|
195
|
+
# File Upload
|
|
196
|
+
MAX_FILE_SIZE=10485760
|
|
197
|
+
UPLOAD_PATH=./uploads
|
|
198
|
+
`;
|
|
199
|
+
|
|
200
|
+
// Add technology-specific env variables
|
|
201
|
+
const techSpecific = {
|
|
202
|
+
python: `
|
|
203
|
+
# Python Specific
|
|
204
|
+
PYTHONPATH=.
|
|
205
|
+
DEBUG=True
|
|
206
|
+
CORS_ORIGINS=http://localhost:3000`,
|
|
207
|
+
|
|
208
|
+
java: `
|
|
209
|
+
# Java Specific
|
|
210
|
+
SPRING_PROFILES_ACTIVE=dev
|
|
211
|
+
SERVER_PORT=8080`,
|
|
212
|
+
|
|
213
|
+
go: `
|
|
214
|
+
# Go Specific
|
|
215
|
+
GIN_MODE=debug`,
|
|
216
|
+
|
|
217
|
+
rust: `
|
|
218
|
+
# Rust Specific
|
|
219
|
+
RUST_LOG=debug`,
|
|
220
|
+
|
|
221
|
+
php: `
|
|
222
|
+
# PHP Specific
|
|
223
|
+
APP_ENV=local
|
|
224
|
+
APP_DEBUG=true
|
|
225
|
+
APP_KEY=base64:your-app-key`
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const specificEnv = techSpecific[config.technology] || '';
|
|
229
|
+
|
|
230
|
+
return commonEnv + specificEnv;
|
|
231
|
+
};
|