argument('module'); $feature_name = $this->argument('feature'); // Validate names (lowercase and underscores only) if (!preg_match('/^[a-z_]+$/', $module_name)) { $this->error('Module name must contain only lowercase letters and underscores.'); return 1; } if (!preg_match('/^[a-z_]+$/', $feature_name)) { $this->error('Feature name must contain only lowercase letters and underscores.'); return 1; } // Check if module exists $module_path = base_path("rsx/app/{$module_name}"); if (!is_dir($module_path)) { $this->error("Module '{$module_name}' does not exist."); $this->line(''); $this->line('NOMENCLATURE:'); $this->line(' Module = Top-level section with shared layout (e.g., frontend, admin)'); $this->line(' Feature = CRUD page group within a module (e.g., clients, tasks)'); $this->line(''); $this->line('Create the module first:'); $this->info(" php artisan rsx:app:module:create {$module_name}"); return 1; } // Determine feature path and naming if ($feature_name === 'index') { // Index feature goes in module root $feature_path = $module_path; $file_prefix = "{$module_name}_index"; } else { // Other features go in subdirectory $feature_path = "{$module_path}/{$feature_name}"; $file_prefix = "{$module_name}_{$feature_name}"; // Check if feature directory already exists if (is_dir($feature_path)) { $this->error("Feature '{$feature_name}' already exists in module '{$module_name}'"); return 1; } // Create feature directory if (!mkdir($feature_path, 0755, true)) { $this->error("Failed to create feature directory: {$feature_path}"); return 1; } } // Check if any feature files already exist $files_to_create = [ "{$feature_path}/{$file_prefix}_controller.php" => 'controller', "{$feature_path}/{$file_prefix}.blade.php" => 'view', "{$feature_path}/{$file_prefix}.js" => 'JavaScript', "{$feature_path}/{$file_prefix}.scss" => 'SCSS', ]; foreach ($files_to_create as $file => $type) { if (file_exists($file)) { $this->error("Cannot create feature '{$feature_name}': {$type} file already exists at {$file}"); return 1; } } $this->info("Creating feature '{$feature_name}' in module '{$module_name}'..."); // Generate replacements $replacements = StubProcessor::generate_replacements($module_name, null, $feature_name); try { // Create controller $controller_content = StubProcessor::process('controller', $replacements); $controller_file = "{$feature_path}/{$file_prefix}_controller.php"; file_put_contents($controller_file, $controller_content); $this->info("Created controller: {$file_prefix}_controller.php"); // Create view $view_content = StubProcessor::process('view', $replacements); $view_file = "{$feature_path}/{$file_prefix}.blade.php"; file_put_contents($view_file, $view_content); $this->info("Created view: {$file_prefix}.blade.php"); // Create JavaScript $js_content = StubProcessor::process('javascript', $replacements); $js_file = "{$feature_path}/{$file_prefix}.js"; file_put_contents($js_file, $js_content); $this->info("Created JavaScript: {$file_prefix}.js"); // Create SCSS $scss_content = StubProcessor::process('scss', $replacements); $scss_file = "{$feature_path}/{$file_prefix}.scss"; file_put_contents($scss_file, $scss_content); $this->info("Created SCSS: {$file_prefix}.scss"); } catch (\Exception $e) { $this->error("Failed to create feature: " . $e->getMessage()); // Clean up on failure if (is_dir($feature_path) && $feature_name !== 'index') { $this->cleanup_directory($feature_path); } return 1; } $this->info("✅ Feature '{$feature_name}' created successfully in module '{$module_name}'!"); $this->info("Route: {$replacements['route_path']}"); $this->info("Controller: {$replacements['controller_class']}"); $this->info("View ID: {$replacements['view_class']}"); return 0; } /** * Clean up directory on failure */ protected function cleanup_directory($dir) { if (!is_dir($dir)) { return; } $files = array_diff(scandir($dir), ['.', '..']); foreach ($files as $file) { $path = $dir . '/' . $file; is_dir($path) ? $this->cleanup_directory($path) : unlink($path); } rmdir($dir); } }