All files / src/commands generateCommand.ts

98.61% Statements 71/72
97.5% Branches 39/40
100% Functions 2/2
100% Lines 70/70

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166                  15x 15x 1x 1x     14x 14x 1x 1x     13x 13x 1x     1x       12x 12x 12x     12x       12x   2x               2x     1x 1x 1x   10x           11x   11x     11x 11x   1x     11x   11x 11x   11x 19x     19x       19x 6x     19x     19x 19x 19x 7x   12x 12x     19x 5x             5x 1x 1x     4x 2x     4x   3x 3x 3x 3x 2x   1x     1x           4x 1x   14x   2x 2x 2x 2x 1x   1x     1x             17x     9x          
import * as path from "node:path";
import * as vscode from "vscode";
import { CanvasPanel } from "../canvas/CanvasPanel";
import { getOutputDirectory } from "../config/ConfigReader";
import { generateJavaFiles } from "../generator/JavaGenerator";
import { inferJavaPackage, resolveOutputDirectory } from "../utils/JavaPackageInference";
import { detectJavaProject } from "../utils/JavaProjectDetector";
 
export function registerGenerateCommand(outputChannel: vscode.OutputChannel): vscode.Disposable {
  return vscode.commands.registerCommand("swingGuiBuilder.generate", async () => {
    if (!CanvasPanel.currentPanel) {
      vscode.window.showErrorMessage("No canvas is open. Open a canvas first.");
      return;
    }
 
    const workspaceFolders = vscode.workspace.workspaceFolders;
    if (!workspaceFolders) {
      vscode.window.showErrorMessage("No workspace folder open.");
      return;
    }
 
    const state = CanvasPanel.currentPanel.getCanvasState();
    if (state.components.length === 0) {
      vscode.window.showWarningMessage(
        "Canvas has no components. Add components before generating.",
      );
      return;
    }
 
    // Determine smart default directory
    const workspaceRoot = workspaceFolders[0].uri.fsPath;
    const projectStructure = detectJavaProject(workspaceRoot);
    const configuredDir = getOutputDirectory();
 
    // Use configured dir if non-default, otherwise use detected project structure
    const defaultDir = resolveOutputDirectory(configuredDir, projectStructure);
 
    let outputDir: string | undefined;
 
    if (!projectStructure && configuredDir === "swing/components/") {
      // No structure detected, no config override — show folder picker
      const pickerResult = await vscode.window.showOpenDialog({
        canSelectFolders: true,
        canSelectFiles: false,
        canSelectMany: false,
        openLabel: "Select output folder for Java files",
        defaultUri: workspaceFolders[0].uri,
      });
 
      if (!pickerResult || pickerResult.length === 0) return;
 
      // Calculate relative path from workspace root
      const selectedPath = pickerResult[0].fsPath;
      const workspacePath = workspaceFolders[0].uri.fsPath;
      outputDir = path.relative(workspacePath, selectedPath);
    } else {
      outputDir = await vscode.window.showInputBox({
        prompt: "Output directory for generated Java files (relative to workspace)",
        value: defaultDir,
      });
    }
 
    Iif (!outputDir) return;
 
    const outputUri = vscode.Uri.joinPath(workspaceFolders[0].uri, outputDir);
 
    // Ensure output directory exists
    try {
      await vscode.workspace.fs.createDirectory(outputUri);
    } catch (_) {
      outputChannel.appendLine(`Note: Directory may already exist: ${outputDir}`);
    }
 
    const javaPackage = inferJavaPackage(outputDir, projectStructure);
 
    const generatedFiles = generateJavaFiles(state, javaPackage);
    let overwriteAll = false;
 
    for (const file of generatedFiles) {
      const targetDirUri = file.subfolder
        ? vscode.Uri.joinPath(outputUri, file.subfolder)
        : outputUri;
      const relativeOutputPath = file.subfolder
        ? `${file.subfolder}/${file.fileName}`
        : file.fileName;
 
      if (file.subfolder) {
        await vscode.workspace.fs.createDirectory(targetDirUri);
      }
 
      const fileUri = vscode.Uri.joinPath(targetDirUri, file.fileName);
 
      // Check if file exists
      let fileExists = false;
      try {
        await vscode.workspace.fs.stat(fileUri);
        fileExists = true;
      } catch (_) {
        fileExists = false;
        outputChannel.appendLine(`Debug: File does not exist yet: ${relativeOutputPath}`);
      }
 
      if (fileExists && !overwriteAll) {
        const choice = await vscode.window.showWarningMessage(
          `${relativeOutputPath} already exists. What do you want to do?`,
          "Overwrite",
          "Overwrite All",
          "Cancel",
        );
 
        if (choice === "Cancel") {
          vscode.window.showInformationMessage("Code generation cancelled.");
          return;
        }
 
        if (choice === "Overwrite All") {
          overwriteAll = true;
        }
 
        if (choice === "Overwrite" || choice === "Overwrite All") {
          // Create backup
          const backupName = file.fileName.replace(".java", "_backup.java");
          const backupUri = vscode.Uri.joinPath(targetDirUri, backupName);
          try {
            const existingContent = await vscode.workspace.fs.readFile(fileUri);
            await vscode.workspace.fs.writeFile(backupUri, existingContent);
          } catch (error) {
            outputChannel.appendLine(
              `Warning: Could not create backup for ${relativeOutputPath}: ${error}`,
            );
            vscode.window.showWarningMessage(
              `Could not create backup for ${relativeOutputPath}. Proceeding without backup.`,
            );
          }
        }
 
        if (!choice) {
          return; // Dialog was dismissed
        }
      } else if (fileExists && overwriteAll) {
        // Create backup for overwrite all
        const backupName = file.fileName.replace(".java", "_backup.java");
        const backupUri = vscode.Uri.joinPath(targetDirUri, backupName);
        try {
          const existingContent = await vscode.workspace.fs.readFile(fileUri);
          await vscode.workspace.fs.writeFile(backupUri, existingContent);
        } catch (error) {
          outputChannel.appendLine(
            `Warning: Could not create backup for ${relativeOutputPath}: ${error}`,
          );
          vscode.window.showWarningMessage(
            `Could not create backup for ${relativeOutputPath}. Proceeding without backup.`,
          );
        }
      }
 
      // Write the file
      await vscode.workspace.fs.writeFile(fileUri, Buffer.from(file.content, "utf-8"));
    }
 
    vscode.window.showInformationMessage(
      `Generated ${generatedFiles.length} Java file(s) in ${outputDir}`,
    );
  });
}