UNPKG

hydra-swe-builder

Version:

A comprehensive CLI tool for creating software engineering projects (Mobile, Frontend, Backend)

1,935 lines (1,668 loc) 66.5 kB
#!/usr/bin/env node const { program } = require('commander'); const inquirer = require('inquirer'); const chalk = require('chalk'); const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const { default: ora } = require('ora'); // ASCII Art Banner const banner = ` ██╗ ██╗██╗ ██╗██████╗ ██████╗ █████╗ ██║ ██║╚██╗ ██╔╝██╔══██╗██╔══██╗██╔══██╗ ███████║ ╚████╔╝ ██║ ██║██████╔╝███████║ ██╔══██║ ╚██╔╝ ██║ ██║██╔══██╗██╔══██║ ██║ ██║ ██║ ██████╔╝██║ ██║██║ ██║ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ███████╗██╗ ██╗███████╗ ██╔════╝██║ ██║██╔════╝ ███████╗██║ █╗ ██║█████╗ ╚════██║██║███╗██║██╔══╝ ███████║╚███╔███╔╝███████╗ ╚══════╝ ╚══╝╚══╝ ╚══════╝ HYDRA (Software Engineering Project Builder) v1.0.0 by Michel Okoubi `; class SEBuilderCLI { constructor() { this.projectTypes = { mobile: { name: 'Mobile Application', icon: '📱', options: [ { name: 'React Native with Expo', value: 'expo' }, { name: 'React Native CLI', value: 'rn-cli' }, { name: 'Native iOS (Swift)', value: 'ios' }, { name: 'Native Android (Kotlin)', value: 'android' } ] }, frontend: { name: 'Frontend Application', icon: '🌐', options: [ { name: 'Angular', value: 'angular' }, { name: 'Next.js', value: 'nextjs' } ] }, backend: { name: 'Backend API', icon: '⚙️', options: [ { name: 'NestJS + Fastify', value: 'nestjs' }, { name: 'Rust + Actix Web', value: 'rust' }, { name: 'Go + Gin', value: 'go' }, { name: 'Quarkus (Java)', value: 'quarkus' } ] }, fullstack: { name: 'Full Stack Project', icon: '🔗', description: 'Complete application with frontend, backend, and mobile' } }; this.apiTypes = [ { name: 'REST API', value: 'rest' }, { name: 'GraphQL', value: 'graphql' }, { name: 'gRPC', value: 'grpc' }, { name: 'WebSocket', value: 'websocket' }, { name: 'All of the above', value: 'all' } ]; } displayBanner() { console.log(chalk.cyan(banner)); console.log(chalk.green("Welcome to Hydra 🚀")); } async interactiveMode() { this.displayBanner(); const { projectType } = await inquirer.prompt([ { type: 'list', name: 'projectType', message: 'What type of project do you want to create?', choices: Object.entries(this.projectTypes).map(([key, config]) => ({ name: `${config.icon} ${config.name}`, value: key, short: config.name })) } ]); const { projectName } = await inquirer.prompt([ { type: 'input', name: 'projectName', message: 'Enter your project name:', validate: (input) => { if (!input.trim()) return 'Project name is required'; if (!/^[a-zA-Z0-9-_]+$/.test(input)) return 'Project name must contain only letters, numbers, hyphens, and underscores'; return true; } } ]); await this.createProject(projectType, projectName); } async createProject(type, name, options = {}) { console.log(chalk.blue(`\n🚀 Creating ${this.projectTypes[type].name}: ${name}`)); switch (type) { case 'mobile': await this.createMobileProject(name, options); break; case 'frontend': await this.createFrontendProject(name, options); break; case 'backend': await this.createBackendProject(name, options); break; case 'fullstack': await this.createFullStackProject(name, options); break; default: console.log(chalk.red('❌ Invalid project type')); process.exit(1); } } async createMobileProject(projectName, options = {}) { let framework = options.framework; if (!framework) { const { selectedFramework } = await inquirer.prompt([ { type: 'list', name: 'selectedFramework', message: 'Select mobile framework:', choices: this.projectTypes.mobile.options } ]); framework = selectedFramework; } const spinner = this.createSpinner(`Creating ${framework} project...`); try { switch (framework) { case 'expo': await this.scaffoldExpoProject(projectName); break; case 'rn-cli': await this.scaffoldRNProject(projectName); break; case 'ios': await this.scaffoldiOSProject(projectName); break; case 'android': await this.scaffoldAndroidProject(projectName); break; } spinner.succeed(chalk.green(`✅ ${framework} project created successfully!`)); this.showPostInstallInstructions(projectName, framework); } catch (error) { spinner.fail(chalk.red(`❌ Error creating project: ${error.message}`)); process.exit(1); } } async createBackendProject(projectName, options = {}) { let framework = options.framework; let apiType = options.apiType; if (!framework) { const { selectedFramework } = await inquirer.prompt([ { type: 'list', name: 'selectedFramework', message: 'Select backend framework:', choices: this.projectTypes.backend.options } ]); framework = selectedFramework; } if (!apiType) { const { selectedApiType } = await inquirer.prompt([ { type: 'list', name: 'selectedApiType', message: 'Select API type:', choices: this.apiTypes } ]); apiType = selectedApiType; } const spinner = this.createSpinner(`Creating ${framework} project with ${apiType}...`); try { switch (framework) { case 'nestjs': await this.scaffoldNestJSProject(projectName, apiType); break; case 'rust': await this.scaffoldRustProject(projectName, apiType); break; case 'go': await this.scaffoldGoProject(projectName, apiType); break; case 'quarkus': await this.scaffoldQuarkusProject(projectName, apiType); break; } spinner.succeed(chalk.green(`✅ ${framework} project created successfully!`)); this.showPostInstallInstructions(projectName, framework); } catch (error) { spinner.fail(chalk.red(`❌ Error creating project: ${error.message}`)); process.exit(1); } } async createFrontendProject(projectName, options = {}) { let framework = options.framework; if (!framework) { const { selectedFramework } = await inquirer.prompt([ { type: 'list', name: 'selectedFramework', message: 'Select frontend framework:', choices: this.projectTypes.frontend.options } ]); framework = selectedFramework; } const spinner = this.createSpinner(`Creating ${framework} project...`); try { switch (framework) { case 'angular': await this.scaffoldAngularProject(projectName); break; case 'nextjs': await this.scaffoldNextJSProject(projectName); break; } spinner.succeed(chalk.green(`✅ ${framework} project created successfully!`)); this.showPostInstallInstructions(projectName, framework); } catch (error) { spinner.fail(chalk.red(`❌ Error creating project: ${error.message}`)); process.exit(1); } } async createFullStackProject(projectName, options = {}) { const spinner = this.createSpinner('Creating full stack project structure...'); try { this.createDirectory(projectName); process.chdir(projectName); // Create project structure await this.scaffoldNextJSProject('frontend'); await this.scaffoldNestJSProject('backend', 'all'); await this.scaffoldExpoProject('mobile'); // Create configuration files this.createDockerCompose(); this.createMonorepoConfig(); this.createReadme(projectName); spinner.succeed(chalk.green('✅ Full stack project created successfully!')); this.showPostInstallInstructions(projectName, 'fullstack'); } catch (error) { spinner.fail(chalk.red(`❌ Error creating project: ${error.message}`)); process.exit(1); } } // Scaffolding methods (simplified versions of the original implementation) async scaffoldExpoProject(projectName) { this.execCommand(`npx create-expo-app@latest ${projectName} --template blank-typescript`); process.chdir(projectName); this.execCommand('npx expo install react-native-screens react-native-safe-area-context'); this.execCommand('npm install @react-navigation/native @react-navigation/stack'); } async scaffoldRNProject(projectName) { this.execCommand(`npx @react-native-community/cli@latest init ${projectName}`); } async scaffoldiOSProject(projectName) { this.createDirectory(projectName); process.chdir(projectName); this.createiOSStructure(projectName); } async scaffoldAndroidProject(projectName) { this.createDirectory(projectName); process.chdir(projectName); this.createAndroidStructure(projectName); } async scaffoldAngularProject(projectName) { this.execCommand(`npx @angular/cli@latest new ${projectName} --routing --style=scss --skip-git`); process.chdir(projectName); this.execCommand('ng add @angular/material --skip-confirmation'); } async scaffoldNextJSProject(projectName) { this.execCommand(`npx create-next-app@latest ${projectName} --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"`); process.chdir(projectName); this.execCommand('npm install lucide-react @radix-ui/react-icons'); } async scaffoldNestJSProject(projectName, apiType) { this.execCommand(`npx @nestjs/cli new ${projectName} --skip-git`); process.chdir(projectName); // Install Fastify this.execCommand('npm install @nestjs/platform-fastify'); // Install API-specific dependencies const deps = this.getBackendDependencies('nestjs', apiType); if (deps.length > 0) { this.execCommand(`npm install ${deps.join(' ')}`); } // Create enhanced main.ts this.createNestJSMain(); } async scaffoldRustProject(projectName, apiType) { this.execCommand(`cargo new ${projectName}`); process.chdir(projectName); const cargoToml = this.generateRustCargoToml(projectName, apiType); this.writeFile('Cargo.toml', cargoToml); const mainRs = this.generateRustMain(apiType); this.writeFile('src/main.rs', mainRs); } async scaffoldGoProject(projectName, apiType) { this.createDirectory(projectName); process.chdir(projectName); this.execCommand(`go mod init ${projectName}`); const deps = this.getBackendDependencies('go', apiType); if (deps.length > 0) { this.execCommand(`go get ${deps.join(' ')}`); } const mainGo = this.generateGoMain(apiType); this.writeFile('main.go', mainGo); } async scaffoldQuarkusProject(projectName, apiType) { const extensions = this.getQuarkusExtensions(apiType); this.execCommand( `mvn io.quarkus.platform:quarkus-maven-plugin:create ` + `-DprojectGroupId=com.example ` + `-DprojectArtifactId=${projectName} ` + `-Dextensions="${extensions}"` ); } // Helper methods createSpinner(message) { // Simple spinner implementation return ora({ text: message, spinner: 'dots', color: 'cyan' }).start(); } execCommand(command) { console.log(chalk.gray(`$ ${command}`)); execSync(command, { stdio: 'inherit' }); } createDirectory(dirName) { if (!fs.existsSync(dirName)) { fs.mkdirSync(dirName, { recursive: true }); } } writeFile(filePath, content) { const dir = path.dirname(filePath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(filePath, content); } getBackendDependencies(framework, apiType) { const deps = { nestjs: { rest: ['@nestjs/swagger', 'swagger-ui-express'], graphql: ['@nestjs/graphql', '@nestjs/apollo', 'apollo-server-fastify', 'graphql'], grpc: ['@nestjs/microservices', '@grpc/grpc-js', '@grpc/proto-loader'], websocket: ['@nestjs/websockets', '@nestjs/platform-socket.io'], all: ['@nestjs/swagger', '@nestjs/graphql', '@nestjs/apollo', '@nestjs/microservices', '@nestjs/websockets'] }, go: { rest: ['github.com/gin-gonic/gin'], graphql: ['github.com/99designs/gqlgen'], grpc: ['google.golang.org/grpc'], websocket: ['github.com/gorilla/websocket'], all: ['github.com/gin-gonic/gin', 'github.com/99designs/gqlgen', 'google.golang.org/grpc', 'github.com/gorilla/websocket'] } }; return deps[framework]?.[apiType] || []; } getQuarkusExtensions(apiType) { const extensions = { rest: 'resteasy-reactive,resteasy-reactive-jackson', graphql: 'resteasy-reactive,smallrye-graphql', grpc: 'grpc', websocket: 'websockets', all: 'resteasy-reactive,resteasy-reactive-jackson,smallrye-graphql,grpc,websockets' }; return extensions[apiType] || extensions.rest; } createDockerCompose() { const dockerCompose = `version: '3.8' services: frontend: build: context: ./frontend dockerfile: Dockerfile ports: - "3000:3000" environment: - NEXT_PUBLIC_API_URL=http://localhost:3001 depends_on: - backend backend: build: context: ./backend dockerfile: Dockerfile ports: - "3001:3001" environment: - DATABASE_URL=postgresql://postgres:password@database:5432/myapp depends_on: - database - redis database: image: postgres:15-alpine ports: - "5432:5432" environment: - POSTGRES_DB=myapp - POSTGRES_USER=postgres - POSTGRES_PASSWORD=password volumes: - postgres_data:/var/lib/postgresql/data redis: image: redis:7-alpine ports: - "6379:6379" volumes: postgres_data: `; this.writeFile('docker-compose.yml', dockerCompose); } createMonorepoConfig() { const packageJson = { name: "fullstack-app", private: true, workspaces: ["frontend", "backend", "mobile"], scripts: { "dev:frontend": "cd frontend && npm run dev", "dev:backend": "cd backend && npm run start:dev", "dev:mobile": "cd mobile && npm start", "build": "npm run build:frontend && npm run build:backend", "build:frontend": "cd frontend && npm run build", "build:backend": "cd backend && npm run build" } }; this.writeFile('package.json', JSON.stringify(packageJson, null, 2)); } createReadme(projectName) { const readme = `# ${projectName} A full-stack application built with modern technologies. ## Structure - \`frontend/\` - Next.js application - \`backend/\` - NestJS API server - \`mobile/\` - React Native (Expo) mobile app ## Getting Started ### Development 1. Install dependencies: \`\`\`bash npm install \`\`\` 2. Start all services: \`\`\`bash docker-compose up --build \`\`\` Or start individually: \`\`\`bash # Frontend npm run dev:frontend # Backend npm run dev:backend # Mobile npm run dev:mobile \`\`\` ## Services - Frontend: http://localhost:3000 - Backend: http://localhost:3001 - API Documentation: http://localhost:3001/api - Database: localhost:5432 - Redis: localhost:6379 ## Technologies ### Frontend - Next.js 14 - TypeScript - Tailwind CSS ### Backend - NestJS - Fastify - PostgreSQL - Redis ### Mobile - React Native - Expo `; this.writeFile('README.md', readme); } showPostInstallInstructions(projectName, projectType) { console.log(chalk.yellow('\n📋 Next Steps:')); console.log(chalk.yellow('================\n')); const instructions = { expo: [ `cd ${projectName}`, 'npm start', '', '📱 Scan QR code with Expo Go app or press (i) for iOS simulator' ], angular: [ `cd ${projectName}`, 'ng serve', '', '🌐 Open http://localhost:4200' ], nextjs: [ `cd ${projectName}`, 'npm run dev', '', '🌐 Open http://localhost:3000' ], nestjs: [ `cd ${projectName}`, 'npm run start:dev', '', '🌐 API: http://localhost:3001', '📚 Docs: http://localhost:3001/api' ], rust: [ `cd ${projectName}`, 'cargo run', '', '🌐 Open http://localhost:8080' ], go: [ `cd ${projectName}`, 'go run main.go', '', '🌐 Open http://localhost:8080' ], quarkus: [ `cd ${projectName}`, './mvnw quarkus:dev', '', '🌐 Open http://localhost:8080' ], fullstack: [ `cd ${projectName}`, 'docker-compose up --build', '', '🌐 Frontend: http://localhost:3000', '🌐 Backend: http://localhost:3001', '📱 Mobile: Run "npm run dev:mobile" separately' ] }; const steps = instructions[projectType] || [`cd ${projectName}`, 'Follow framework-specific instructions']; steps.forEach(step => { if (step === '') { console.log(); } else if (step.startsWith('🌐') || step.startsWith('📚') || step.startsWith('📱')) { console.log(chalk.green(step)); } else { console.log(chalk.cyan(step)); } }); console.log(chalk.magenta('\n✨ Happy coding! ✨')); } // Template generators (simplified versions) createNestJSMain() { const mainTs = `import { NestFactory } from '@nestjs/core'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; import { AppModule } from './app.module'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter({ logger: true }) ); // Enable CORS await app.register(require('@fastify/cors'), { origin: true, credentials: true, }); // Swagger Documentation const config = new DocumentBuilder() .setTitle('API Documentation') .setDescription('Generated API documentation') .setVersion('1.0') .addBearerAuth() .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api', app, document); const port = process.env.PORT || 3001; await app.listen(port, '0.0.0.0'); console.log(\`🚀 Server running on http://localhost:\${port}\`); console.log(\`📚 API Documentation: http://localhost:\${port}/api\`); } bootstrap(); `; this.writeFile('src/main.ts', mainTs); } generateRustCargoToml(projectName, apiType) { let dependencies = `[dependencies] actix-web = "4.4" tokio = { version = "1.35", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" env_logger = "0.10"`; if (apiType === 'graphql' || apiType === 'all') { dependencies += '\njuniper = "0.16"'; } if (apiType === 'grpc' || apiType === 'all') { dependencies += '\ntonic = "0.10"\nprost = "0.12"'; } return `[package] name = "${projectName}" version = "0.1.0" edition = "2021" ${dependencies} `; } generateRustMain(apiType) { return `use actix_web::{web, App, HttpResponse, HttpServer, Result, middleware::Logger}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct ApiResponse { message: String, status: String, } async fn health() -> Result<HttpResponse> { Ok(HttpResponse::Ok().json(ApiResponse { message: "Server is running".to_string(), status: "OK".to_string(), })) } #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init(); println!("🦀 Starting Rust server on http://localhost:8080"); HttpServer::new(|| { App::new() .wrap(Logger::default()) .route("/health", web::get().to(health)) .route("/", web::get().to(|| async { HttpResponse::Ok().json(ApiResponse { message: "Welcome to Rust API".to_string(), status: "OK".to_string(), }) })) }) .bind("127.0.0.1:8080")? .run() .await } `; } generateGoMain(apiType) { return `package main import ( "net/http" "github.com/gin-gonic/gin" ) type ApiResponse struct { Message string \`json:"message"\` Status string \`json:"status"\` } func main() { r := gin.Default() // CORS middleware r.Use(func(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() }) r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, ApiResponse{ Message: "Welcome to Go API", Status: "OK", }) }) r.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, ApiResponse{ Message: "Server is running", Status: "OK", }) }) println("🐹 Starting Go server on http://localhost:8080") r.Run(":8080") } `; } createiOSStructure(projectName) { // Create basic iOS project files const files = { 'Package.swift': this.getiOSPackageSwift(projectName), 'Sources/App.swift': this.getiOSAppSwift(projectName), 'Sources/ContentView.swift': this.getiOSContentView(), 'README.md': `# ${projectName}\n\nAn iOS application built with SwiftUI.` }; Object.entries(files).forEach(([path, content]) => { this.writeFile(path, content); }); } createAndroidStructure(projectName) { // Create basic Android project structure const files = { 'app/src/main/kotlin/MainActivity.kt': this.getAndroidMainActivity(projectName), 'app/src/main/res/layout/activity_main.xml': this.getAndroidMainLayout(), 'app/build.gradle.kts': this.getAndroidBuildGradle(projectName), 'settings.gradle.kts': `rootProject.name = "${projectName}"\\ninclude(":app")`, 'README.md': `# ${projectName}\n\nAn Android application built with Kotlin.` }; Object.entries(files).forEach(([path, content]) => { this.writeFile(path, content); }); } // iOS Templates getiOSPackageSwift(projectName) { return `// swift-tools-version: 5.9 import PackageDescription let package = Package( name: "${projectName}", platforms: [ .iOS(.v16) ], products: [ .library(name: "${projectName}", targets: ["${projectName}"]) ], targets: [ .target(name: "${projectName}") ] ) `; } getiOSAppSwift(projectName) { return `import SwiftUI @main struct ${projectName}App: App { var body: some Scene { WindowGroup { ContentView() } } } `; } getiOSContentView() { return `import SwiftUI struct ContentView: View { var body: some View { VStack(spacing: 20) { Image(systemName: "swift") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, SwiftUI!") .font(.title) .fontWeight(.bold) Text("Welcome to your new iOS app") .font(.subheadline) .foregroundStyle(.secondary) } .padding() } } #Preview { ContentView() } `; } // Android Templates getAndroidMainActivity(projectName) { return `package com.example.${projectName.toLowerCase()} import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.example.${projectName.toLowerCase()}.ui.theme.${projectName}Theme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ${projectName}Theme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { MainScreen() } } } } } @Composable fun MainScreen() { Column( modifier = Modifier .fillMaxSize() .padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( text = "Hello, Android!", style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.height(16.dp)) Text( text = "Welcome to your new Kotlin app", style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.onSurfaceVariant ) } } @Preview(showBackground = true) @Composable fun MainScreenPreview() { ${projectName}Theme { MainScreen() } } `; } getAndroidMainLayout() { return `<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, Android!" android:textSize="24sp" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> `; } getAndroidBuildGradle(projectName) { return `plugins { id("com.android.application") id("org.jetbrains.kotlin.android") } android { namespace = "com.example.${projectName.toLowerCase()}" compileSdk = 34 defaultConfig { applicationId = "com.example.${projectName.toLowerCase()}" minSdk = 24 targetSdk = 34 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true } } buildTypes { release { isMinifyEnabled = false proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.4" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } } dependencies { implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0") implementation("androidx.activity:activity-compose:1.8.2") implementation(platform("androidx.compose:compose-bom:2023.10.01")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.material3:material3") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01")) androidTestImplementation("androidx.compose.ui:ui-test-junit4") debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-test-manifest") } `; } // Web Templates getWebPackageJson(projectName) { return `{ "name": "${projectName.toLowerCase()}", "version": "1.0.0", "description": "A modern web application", "main": "index.js", "scripts": { "start": "webpack serve --mode development", "build": "webpack --mode production", "test": "jest", "lint": "eslint src/" }, "keywords": ["web", "javascript", "webpack"], "author": "HYDRA Software Engineering", "license": "MIT", "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@babel/core": "^7.22.0", "@babel/preset-env": "^7.22.0", "@babel/preset-react": "^7.22.0", "babel-loader": "^9.1.0", "css-loader": "^6.8.0", "html-webpack-plugin": "^5.5.0", "style-loader": "^3.3.0", "webpack": "^5.88.0", "webpack-cli": "^5.1.0", "webpack-dev-server": "^4.15.0", "eslint": "^8.44.0", "jest": "^29.6.0" } } `; } getWebIndexHtml(projectName) { return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${projectName}</title> </head> <body> <div id="root"></div> </body> </html> `; } getWebIndexJs() { return `import React from 'react'; import ReactDOM from 'react-dom/client'; import './styles.css'; const App = () => { return ( <div className="app"> <header className="app-header"> <h1>Welcome to Your Web App</h1> <p>Built with React and Webpack</p> <button className="cta-button">Get Started</button> </header> </div> ); }; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />); `; } getWebStyles() { return `* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; line-height: 1.6; color: #333; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; } .app { display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; } .app-header { text-align: center; background: rgba(255, 255, 255, 0.95); padding: 3rem 2rem; border-radius: 20px; box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); backdrop-filter: blur(10px); max-width: 600px; } .app-header h1 { font-size: 2.5rem; margin-bottom: 1rem; background: linear-gradient(135deg, #667eea, #764ba2); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .app-header p { font-size: 1.2rem; margin-bottom: 2rem; color: #666; } .cta-button { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; padding: 12px 30px; font-size: 1.1rem; border-radius: 50px; cursor: pointer; transition: transform 0.3s ease, box-shadow 0.3s ease; font-weight: 600; } .cta-button:hover { transform: translateY(-2px); box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3); } `; } getWebpackConfig() { return `const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: '[name].[contenthash].js', clean: true, }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'], }, }, }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, ], }, plugins: [ new HtmlWebpackPlugin({ template: './public/index.html', }), ], devServer: { contentBase: path.join(__dirname, 'dist'), port: 3000, hot: true, open: true, }, resolve: { extensions: ['.js', '.jsx'], }, }; `; } // API Templates getAPIPackageJson(projectName) { return `{ "name": "${projectName.toLowerCase()}-api", "version": "1.0.0", "description": "RESTful API built with Node.js and Express", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js", "test": "jest" }, "keywords": ["api", "nodejs", "express", "rest"], "author": "HYDRA Software Engineering", "license": "MIT", "dependencies": { "express": "^4.18.0", "cors": "^2.8.5", "helmet": "^7.0.0", "morgan": "^1.10.0", "dotenv": "^16.3.0", "mongoose": "^7.4.0" }, "devDependencies": { "nodemon": "^3.0.0", "jest": "^29.6.0", "supertest": "^6.3.0" } } `; } getAPIServer() { return `const express = require('express'); const cors = require('cors'); const helmet = require('helmet'); const morgan = require('morgan'); require('dotenv').config(); const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(helmet()); app.use(cors()); app.use(morgan('combined')); app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true })); // Routes app.get('/', (req, res) => { res.json({ message: 'Welcome to your API', version: '1.0.0', endpoints: { health: '/health', api: '/api/v1' } }); }); app.get('/health', (req, res) => { res.json({ status: 'OK', timestamp: new Date().toISOString(), uptime: process.uptime() }); }); // API Routes app.use('/api/v1', require('./routes/api')); // Error handling middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: 'Something went wrong!', message: process.env.NODE_ENV === 'development' ? err.message : 'Internal server error' }); }); // 404 handler app.use('*', (req, res) => { res.status(404).json({ error: 'Route not found', path: req.originalUrl }); }); app.listen(PORT, () => { console.log(\`🚀 Server running on port \${PORT}\`); console.log(\`📚 API documentation: http://localhost:\${PORT}\`); }); module.exports = app; `; } getAPIRoutes() { return `const express = require('express'); const router = express.Router(); // Sample data (replace with database) let items = [ { id: 1, name: 'Item 1', description: 'First sample item' }, { id: 2, name: 'Item 2', description: 'Second sample item' } ]; // GET /api/v1/items router.get('/items', (req, res) => { res.json({ success: true, data: items, count: items.length }); }); // GET /api/v1/items/:id router.get('/items/:id', (req, res) => { const item = items.find(i => i.id === parseInt(req.params.id)); if (!item) { return res.status(404).json({ success: false, error: 'Item not found' }); } res.json({ success: true, data: item }); }); // POST /api/v1/items router.post('/items', (req, res) => { const { name, description } = req.body; if (!name) { return res.status(400).json({ success: false, error: 'Name is required' }); } const newItem = { id: items.length + 1, name, description: description || '' }; items.push(newItem); res.status(201).json({ success: true, data: newItem }); }); // PUT /api/v1/items/:id router.put('/items/:id', (req, res) => { const itemIndex = items.findIndex(i => i.id === parseInt(req.params.id)); if (itemIndex === -1) { return res.status(404).json({ success: false, error: 'Item not found' }); } const { name, description } = req.body; items[itemIndex] = { ...items[itemIndex], name: name || items[itemIndex].name, description: description !== undefined ? description : items[itemIndex].description }; res.json({ success: true, data: items[itemIndex] }); }); // DELETE /api/v1/items/:id router.delete('/items/:id', (req, res) => { const itemIndex = items.findIndex(i => i.id === parseInt(req.params.id)); if (itemIndex === -1) { return res.status(404).json({ success: false, error: 'Item not found' }); } items.splice(itemIndex, 1); res.json({ success: true, message: 'Item deleted successfully' }); }); module.exports = router; `; } // Desktop Templates (Electron) getDesktopPackageJson(projectName) { return `{ "name": "${projectName.toLowerCase()}-desktop", "version": "1.0.0", "description": "Desktop application built with Electron", "main": "main.js", "scripts": { "start": "electron .", "dev": "electron . --dev", "build": "electron-builder", "build-win": "electron-builder --win", "build-mac": "electron-builder --mac", "build-linux": "electron-builder --linux" }, "keywords": ["electron", "desktop", "cross-platform"], "author": "HYDRA Software Engineering", "license": "MIT", "dependencies": { "electron": "^25.3.0" }, "devDependencies": { "electron-builder": "^24.6.3" }, "build": { "appId": "com.example.${projectName.toLowerCase()}", "productName": "${projectName}", "directories": { "output": "dist" }, "files": [ "main.js", "renderer.js", "styles.css", "index.html" ] } } `; } getDesktopMain() { return `const { app, BrowserWindow, Menu } = require('electron'); const path = require('path'); let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { nodeIntegration: true, contextIsolation: false }, icon: path.join(__dirname, 'assets/icon.png'), titleBarStyle: 'default', show: false }); mainWindow.loadFile('index.html'); // Show window when ready mainWindow.once('ready-to-show', () => { mainWindow.show(); }); // Open DevTools in development if (process.argv.includes('--dev')) { mainWindow.webContents.openDevTools(); } mainWindow.on('closed', () => { mainWindow = null; }); } // Create application menu const template = [ { label: 'File', submenu: [ { label: 'New', accelerator: 'CmdOrCtrl+N', click: () => { console.log('New file'); } }, { label: 'Open', accelerator: 'CmdOrCtrl+O', click: () => { console.log('Open file'); } }, { type: 'separator' }, { role: 'quit' } ] }, { label: 'Edit', submenu: [ { role: 'undo' }, { role: 'redo' }, { type: 'separator' }, { role: 'cut' }, { role: 'copy' }, { role: 'paste' } ] }, { label: 'View', submenu: [ { role: 'reload' }, { role: 'forceReload' }, { role: 'toggleDevTools' }, { type: 'separator' }, { role: 'actualSize' }, { role: 'zoomIn' }, { role: 'zoomOut' }, { type: 'separator' }, { role: 'togglefullscreen' } ] }, { label: 'Help', submenu: [ { label: 'About', click: () => { console.log('About'); } } ] } ]; app.whenReady().then(() => { const menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); `; } getDesktopRenderer() { return `// Renderer process code document.addEventListener('DOMContentLoaded', () => { console.log('Desktop app loaded!'); // Add click event to the main button const button = document.getElementById('main-button'); if (button) { button.addEventListener('click', () => { button.textContent = 'Clicked!'; setTimeout(() => { button.textContent = 'Click me!'; }, 1000); }); } // Display system info const systemInfo = document.getElementById('system-info'); if (systemInfo) { const info = { platform: process.platform, arch: process.arch, nodeVersion: process.versions.node, electronVersion: process.versions.electron }; systemInfo.innerHTML = \` <h3>System Information</h3> <p><strong>Platform:</strong> \${info.platform}</p> <p><strong>Architecture:</strong> \${info.arch}</p> <p><strong>Node.js:</strong> \${info.nodeVersion}</p> <p><strong>Electron:</strong> \${info.electronVersion}</p> \`; } }); `; } getDesktopHTML(projectName) { return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${projectName}</title> <link rel="stylesheet" href="styles.css"> </head> <body> <div class="container"> <header class="app-header"> <h1>Welcome to ${projectName}</h1> <p>Your cross-platform desktop application</p> </header> <main class="app-main"> <div class="card"> <h2>Getting Started</h2> <p>This is your Electron desktop application. You can build cross-platform apps with web technologies.</p> <button id="main-button" class="btn-primary">Click me!</button> </div> <div class="card" id="system-info"> <!-- System info will be populated by renderer.js --> </div> </main> <footer class="app-footer"> <p>Built with ❤️ using Electron</p> </footer> </div> <script src="renderer.js"></script> </body> </html> `; } getDesktopCSS() { return `* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; line-height: 1.6; color: #333; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; } .container { max-width: 1000px; margin: 0 auto; padding: 20px; min-height: 100vh; display: flex; flex-direction: column; } .app-header { text-align: center; padding: 2rem 0; } .app-header h1 { font-size: 3rem; margin-bottom: 0.5rem; color: white; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); } .app-header p { font-size: 1.3rem; color: rgba(255, 255, 255, 0.9); } .app-main { flex: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 2rem; margin: 2rem 0; } .card { background: rgba(255, 255, 255, 0.95); padding: 2rem; border-radius: 15px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); backdrop-filter: blur(10px); transition: transform 0.3s ease; } .card:hover { transform: translateY(-5px); } .card h2 { color: #333; margin-bottom: 1rem; font-size: 1.8rem; } .card h3 { color: #555; margin-bottom: 1rem; font-size: 1.4rem; } .card p { color: #666; margin-bottom: 1.5rem; } .btn-primary { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; padding: 12px 24px; font-size: 1rem; border-radius: 25px; cursor: pointer; transition: all 0.3s ease; font-weight: 600; } .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3); } .app-footer { text-align: center; padding: 1rem 0; color: rgba(255, 255, 255, 0.8); border-top: 1px solid rgba(255, 255, 255, 0.1); margin-top: 2rem; } `; } // Template Generators generateWebProject(projectName) { console.log(chalk.blue('📦 Creating Web project structure...')); const files = { 'package.json': this.getWebPackageJson(projectName), 'webpack.config.js': this.getWebpackConfig(), 'public/index.html': this.getWebIndexHtml(projectName), 'src/index.js': this.getWebIndexJs(), 'src/styles.css': this.getWebStyles(), '.gitignore': this.getGitignore('web'), 'README.md': this.getWebReadme(projectName) }; Object.entries(files).forEach(([path, content]) => { this.writeFile(path, content); }); console.log(chalk.green('✅ Web project created successfully!')); this.showWebInstructions(projectName); } generateMobileProject(projectName, platform) { console.log(chalk.blue(`📱 Creating ${platform} mobile project structure...`)); if (platform === 'ios') { this.createiOSStructure(projectName); this.showIOSInstructions(projectName); } else if (platform === 'android') { this.createAndroidStructure(projectName); this.showAndroidInstructions(projectName); } else { // React Native this.createReactNativeStructure(projectName); this.showReactNativeInstructions(projectName); } console.log(chalk.green('✅ Mobile project created successfully!')); } generateDesktopProject(projectName) { console.log(chalk.blue('🖥️ Creating Desktop project structure...')); const files = { 'package.json': this.getDesktopPackageJson(projectName), 'main.js': this.getDesktopMain(), 'renderer.js': this.getDesktopRenderer(), 'index.html': this.getDesktopHTML(projectName), 'styles.css': this.getDesktopCSS(), '.gitignore': this.getGitignore('desktop'), 'README.md': this.getDesktopReadme(projectName) }; Object.entries(files).forEach(([path, content]) => { this.writeFile(path, content); }); console.log(chalk.green('✅ Desktop project created successfully!')); this.showDesktopInstructions(projectName); } generateAPIProject(projectName) { console.log(chalk.blue('🚀 Creating API project structure...')); const files = { 'package.json': this.getAPIPackageJson(projectName), 'server.js': this.getAPIServer(), 'routes/api.js': this.getAPIRoutes(), '.env': this.getEnvFile(), '.gitignore': this.getGitignore('api'), 'README.md': this.getAPIReadme(projectName) }; Object.entries(files).forEach(([path, content]) => { this.writeFile(path, content); }); console.log(chalk.green('✅ API project created successfully!')); this.showAPIInstructions(projectName); } generateFullStackProject(projectName) { console.log(chalk.blue('🌐 Creating Full-Stack project structure...')); // Create client and server directories const clientFiles = { 'client/package.json': this.getWebPackageJson(projectName + '-client'), 'client/webpack.config.js': this.getWebpackConfig(), 'client/public/index.html': this.getWebIndexHtml(projectName), 'client/src/index.js': this.getFullStackClientJS(), 'client/src/styles.css': this.getWebStyles(), 'client/.gitignore': this.getGitignore('web') }; const serverFiles = { 'server/package.json': this.getAPIPackageJson(projectName + '-server'), 'server/server.js': this.getAPIServer(), 'server/routes/api.js': this.getAPIRoutes(), 'server/.env': this.getEnvFile(), 'server/.gitignore': this.getGitignore('api') }; const rootFiles = { 'package.json': this.getFullStackRootPackage(projectName), 'README.md': this.getFullStackReadme(projectName), '.gitignore': this.getGitignore('fullstack') }; [...Object.entries(clientFiles), ...Object.entries(serverFiles), ...Object.entries(rootFiles)] .forEach(([path, content]) => { this.writeFile(path, content); }); console.log(chalk.green('✅ Full-Stack project created successfully!')); this.showFullStackInstructions(projectName); } // React Native structure createReactNativeStructure(projectName) { const files = { 'package.json': this.getReactNativePackage(projectName), 'App.js': this.getReactNativeApp(), 'index.js': this.getReactNativeIndex