@archznn/xavva 2.0.3 → 2.1.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.
@@ -2,6 +2,9 @@ import type { Command } from "./Command";
2
2
  import type { AppConfig, CLIArguments } from "../types/config";
3
3
  import { Logger } from "../utils/ui";
4
4
  import path from "path";
5
+ import fs from "fs";
6
+ import { glob } from "glob";
7
+ import readline from "readline";
5
8
 
6
9
  export class RunCommand implements Command {
7
10
  async execute(config: AppConfig, args?: CLIArguments): Promise<void> {
@@ -39,6 +42,10 @@ export class RunCommand implements Command {
39
42
  "-classpath", finalCp,
40
43
  ];
41
44
 
45
+ if (config.project.encoding) {
46
+ javaArgs.push(`-Dfile.encoding=${config.project.encoding}`);
47
+ }
48
+
42
49
  if (isDebug) {
43
50
  javaArgs.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005");
44
51
  }
@@ -70,8 +77,6 @@ export class RunCommand implements Command {
70
77
  }
71
78
 
72
79
  private async discoverClass(simpleName: string): Promise<string | null> {
73
- const fs = require("fs");
74
- const glob = require("glob");
75
80
  const basePaths = [
76
81
  path.join(process.cwd(), "src/main/java"),
77
82
  path.join(process.cwd(), "src/test/java"),
@@ -134,14 +139,14 @@ export class RunCommand implements Command {
134
139
  Logger.log(` [${i + 1}] ${c}`);
135
140
  });
136
141
 
137
- const readline = require("readline").createInterface({
142
+ const rl = readline.createInterface({
138
143
  input: process.stdin,
139
144
  output: process.stdout
140
145
  });
141
146
 
142
147
  return new Promise((resolve) => {
143
- readline.question(` Escolha a classe (1-${uniqueClasses.length}) ou [C]ancelar: `, (answer: string) => {
144
- readline.close();
148
+ rl.question(` Escolha a classe (1-${uniqueClasses.length}) ou [C]ancelar: `, (answer: string) => {
149
+ rl.close();
145
150
  const idx = parseInt(answer) - 1;
146
151
  if (!isNaN(idx) && uniqueClasses[idx]) {
147
152
  resolve(uniqueClasses[idx]);
@@ -154,7 +159,6 @@ export class RunCommand implements Command {
154
159
  }
155
160
 
156
161
  private async loadFromHistory(): Promise<string | null> {
157
- const fs = require("fs");
158
162
  const xavvaDir = path.join(process.cwd(), ".xavva");
159
163
  const historyFile = path.join(xavvaDir, "history.json");
160
164
 
@@ -169,14 +173,14 @@ export class RunCommand implements Command {
169
173
  Logger.log(` [${i + 1}] ${c}${i === 0 ? " (Enter)" : ""}`);
170
174
  });
171
175
 
172
- const readline = require("readline").createInterface({
176
+ const rl = readline.createInterface({
173
177
  input: process.stdin,
174
178
  output: process.stdout
175
179
  });
176
180
 
177
181
  return new Promise((resolve) => {
178
- readline.question(` Escolha a classe (1-${Math.min(history.length, 5)}) ou [C]ancelar: `, (answer: string) => {
179
- readline.close();
182
+ rl.question(` Escolha a classe (1-${Math.min(history.length, 5)}) ou [C]ancelar: `, (answer: string) => {
183
+ rl.close();
180
184
  if (!answer.trim()) {
181
185
  resolve(history[0]);
182
186
  return;
@@ -195,7 +199,6 @@ export class RunCommand implements Command {
195
199
  }
196
200
 
197
201
  private saveToHistory(className: string) {
198
- const fs = require("fs");
199
202
  const xavvaDir = path.join(process.cwd(), ".xavva");
200
203
  const historyFile = path.join(xavvaDir, "history.json");
201
204
 
@@ -214,7 +217,6 @@ export class RunCommand implements Command {
214
217
  }
215
218
 
216
219
  private async createPathingJar(dependencyCp: string): Promise<string> {
217
- const fs = require("fs");
218
220
  const xavvaDir = path.join(process.cwd(), ".xavva");
219
221
  const jarPath = path.join(xavvaDir, "classpath.jar");
220
222
 
@@ -285,7 +287,6 @@ export class RunCommand implements Command {
285
287
  }
286
288
 
287
289
  private async getClasspath(config: AppConfig): Promise<{ localCp: string, dependencyCp: string }> {
288
- const fs = require("fs");
289
290
  const xavvaDir = path.join(process.cwd(), ".xavva");
290
291
  const cpFile = path.join(xavvaDir, "classpath.txt");
291
292
 
@@ -2,6 +2,7 @@ import type { Command } from "./Command";
2
2
  import type { AppConfig } from "../types/config";
3
3
  import { TomcatService } from "../services/TomcatService";
4
4
  import { Logger } from "../utils/ui";
5
+ import { ProcessManager } from "../utils/processManager";
5
6
 
6
7
  export class StartCommand implements Command {
7
8
  constructor(private tomcat: TomcatService) {}
@@ -20,9 +21,10 @@ export class StartCommand implements Command {
20
21
  tomcat.start(config, false);
21
22
 
22
23
  await new Promise(() => {});
23
- } catch (error: any) {
24
- Logger.error(error.message);
25
- process.exit(1);
24
+ } catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ Logger.error(message);
27
+ await ProcessManager.getInstance().shutdown(1);
26
28
  }
27
29
  }
28
30
  }
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ import { LogsCommand } from "./commands/LogsCommand";
11
11
  import { DocsCommand } from "./commands/DocsCommand";
12
12
  import { AuditCommand } from "./commands/AuditCommand";
13
13
  import { ProfilesCommand } from "./commands/ProfilesCommand";
14
+ import { DepsCommand } from "./commands/DepsCommand";
14
15
 
15
16
  import { ProjectService } from "./services/ProjectService";
16
17
  import { TomcatService } from "./services/TomcatService";
@@ -23,26 +24,31 @@ import { LogAnalyzer } from "./services/LogAnalyzer";
23
24
 
24
25
  import pkg from "../package.json";
25
26
  import { Logger } from "./utils/ui";
27
+ import { ProcessManager } from "./utils/processManager";
26
28
  import type { AppConfig, CLIArguments } from "./types/config";
27
29
 
28
30
  async function main() {
31
+ const processManager = ProcessManager.getInstance();
29
32
  const { config, positionals, values } = await ConfigManager.load();
30
33
 
31
34
  if (values.version) {
32
35
  Logger.log(`v${pkg.version}`);
33
- process.exit(0);
36
+ await processManager.shutdown(0);
34
37
  }
35
38
 
36
- const commandNames = ["deploy", "build", "start", "dev", "doctor", "run", "debug", "logs", "docs", "audit", "profiles"];
39
+ const commandNames = ["deploy", "build", "start", "dev", "doctor", "run", "debug", "logs", "docs", "audit", "profiles", "deps"];
37
40
  const commandName = positionals.find(p => commandNames.includes(p)) || "deploy";
38
41
 
39
42
  if (!values.help && !values.tui) {
40
- Logger.banner(commandName, config.project.profile);
43
+ Logger.banner(commandName, config.project.profile, config.project.encoding);
44
+ if (config.project.encoding) {
45
+ Logger.config("Encoding", config.project.encoding);
46
+ }
41
47
  }
42
48
 
43
49
  if (values.help) {
44
50
  new HelpCommand().execute(config, values);
45
- process.exit(0);
51
+ await processManager.shutdown(0);
46
52
  }
47
53
 
48
54
  // 1. Instanciar Serviços (Injeção de Dependência)
@@ -73,6 +79,7 @@ async function main() {
73
79
  registry.register("docs", new DocsCommand());
74
80
  registry.register("audit", new AuditCommand(auditService));
75
81
  registry.register("profiles", new ProfilesCommand(projectService));
82
+ registry.register("deps", new DepsCommand());
76
83
  registry.register("deploy", deployCmd);
77
84
  registry.register("dev", deployCmd);
78
85
 
@@ -97,4 +104,7 @@ async function main() {
97
104
  }
98
105
  }
99
106
 
100
- main().catch(console.error);
107
+ main().catch(async (error) => {
108
+ console.error(error);
109
+ await ProcessManager.getInstance().shutdown(1);
110
+ });
@@ -19,6 +19,32 @@ export interface JarAuditResult {
19
19
  vulnerabilities: Vulnerability[];
20
20
  }
21
21
 
22
+ // Interfaces para resposta da OSV API
23
+ interface OSVEvent {
24
+ fixed?: string;
25
+ }
26
+
27
+ interface OSVRange {
28
+ events: OSVEvent[];
29
+ }
30
+
31
+ interface OSVAffected {
32
+ ranges: OSVRange[];
33
+ }
34
+
35
+ interface OSVVulnerability {
36
+ id: string;
37
+ summary?: string;
38
+ details?: string;
39
+ affected?: OSVAffected[];
40
+ database_specific?: { severity?: string };
41
+ advisories?: { url: string }[];
42
+ }
43
+
44
+ interface OSVResponse {
45
+ vulns?: OSVVulnerability[];
46
+ }
47
+
22
48
  export class AuditService {
23
49
  constructor(private tomcatConfig: TomcatConfig) {}
24
50
 
@@ -120,22 +146,22 @@ export class AuditService {
120
146
  })
121
147
  });
122
148
 
123
- const data = await response.json();
149
+ const data = (await response.json()) as OSVResponse;
124
150
  if (!data.vulns) return [];
125
151
 
126
- return data.vulns.map((v: any) => ({
152
+ return data.vulns.map((v) => ({
127
153
  id: v.id,
128
154
  summary: v.summary || v.details?.substring(0, 100) + "...",
129
155
  details: v.details,
130
156
  severity: this.extractSeverity(v),
131
- fixedIn: v.affected?.[0]?.ranges?.[0]?.events?.find((e: any) => e.fixed)?.fixed
157
+ fixedIn: v.affected?.[0]?.ranges?.[0]?.events?.find((e) => e.fixed)?.fixed
132
158
  }));
133
159
  } catch (e) {
134
160
  return [];
135
161
  }
136
162
  }
137
163
 
138
- private extractSeverity(vuln: any): string {
164
+ private extractSeverity(vuln: OSVVulnerability): string {
139
165
  if (vuln.database_specific?.severity) return vuln.database_specific.severity;
140
166
  if (vuln.advisories?.[0]?.url?.includes("github.com/advisories")) {
141
167
  const d = (vuln.details || "").toLowerCase();
@@ -1,6 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import crypto from "crypto";
4
+ import type { ProjectService } from "./ProjectService";
4
5
 
5
6
  export interface CacheData {
6
7
  lastConfigHash: string;
@@ -41,7 +42,7 @@ export class BuildCacheService {
41
42
  return crypto.createHash("md5").update(hash).digest("hex");
42
43
  }
43
44
 
44
- shouldRebuild(tool: "maven" | "gradle", projectService?: any): boolean {
45
+ shouldRebuild(tool: "maven" | "gradle", projectService?: ProjectService): boolean {
45
46
  if (!fs.existsSync(this.cacheFile)) return true;
46
47
 
47
48
  try {
@@ -38,7 +38,7 @@ export class BuildService {
38
38
  }
39
39
 
40
40
  const command = [];
41
- const env: any = { ...process.env };
41
+ const env: Record<string, string | undefined> = { ...process.env };
42
42
 
43
43
  if (this.projectConfig.buildTool === 'maven') {
44
44
  command.push(process.platform === "win32" ? "mvn.cmd" : "mvn");
@@ -57,6 +57,10 @@ export class BuildService {
57
57
  }
58
58
  command.push("-Dmaven.test.skip=true", "-Dmaven.javadoc.skip=true");
59
59
  if (this.projectConfig.profile) command.push(`-P${this.projectConfig.profile}`);
60
+ if (this.projectConfig.encoding) {
61
+ command.push(`-Dproject.build.sourceEncoding=${this.projectConfig.encoding}`);
62
+ command.push(`-Dproject.reporting.outputEncoding=${this.projectConfig.encoding}`);
63
+ }
60
64
 
61
65
  env.MAVEN_OPTS = "-Xms512m -Xmx1024m -XX:+UseParallelGC";
62
66
  } else {
@@ -70,6 +74,9 @@ export class BuildService {
70
74
  }
71
75
  command.push("-x", "test", "-x", "javadoc");
72
76
  if (this.projectConfig.profile) command.push(`-Pprofile=${this.projectConfig.profile}`);
77
+ if (this.projectConfig.encoding) {
78
+ command.push(`-Dfile.encoding=${this.projectConfig.encoding}`);
79
+ }
73
80
 
74
81
  env.GRADLE_OPTS = "-Xmx1024m -Dorg.gradle.daemon=true";
75
82
  }
@@ -1,4 +1,10 @@
1
1
  import { Logger } from "../utils/ui";
2
+ import { ProcessManager } from "../utils/processManager";
3
+ import {
4
+ MAX_LOG_SCROLLBUFFER,
5
+ DASHBOARD_REFRESH_INTERVAL_MS,
6
+ DASHBOARD_LOG_SLICE_LINES
7
+ } from "../utils/constants";
2
8
  import type { AppConfig } from "../types/config";
3
9
  import os from "os";
4
10
 
@@ -8,7 +14,7 @@ export class DashboardService {
8
14
  private maxLogLines: number = 0;
9
15
  private status: string = "IDLE";
10
16
  private statusColor: string = Logger.C.dim;
11
- private gitContext: any = null;
17
+ private gitContext: { branch: string; commit: string } | null = null;
12
18
  private actions: Map<string, () => void> = new Map();
13
19
 
14
20
  constructor(private config: AppConfig) {
@@ -17,6 +23,23 @@ export class DashboardService {
17
23
  this.gitContext = Logger.getGitContext();
18
24
  this.maxLogLines = process.stdout.rows - 6;
19
25
  this.setupTui();
26
+ this.registerShutdownHandlers();
27
+ }
28
+ }
29
+
30
+ private registerShutdownHandlers() {
31
+ const processManager = ProcessManager.getInstance();
32
+ processManager.onShutdown(() => {
33
+ this.restoreTerminal();
34
+ });
35
+ }
36
+
37
+ private restoreTerminal() {
38
+ if (this.isTui) {
39
+ process.stdout.write("\x1B[?1049l"); // Restore buffer
40
+ process.stdout.write("\x1B[?25h"); // Show cursor
41
+ process.stdin.setRawMode(false);
42
+ process.stdin.pause();
20
43
  }
21
44
  }
22
45
 
@@ -72,8 +95,8 @@ export class DashboardService {
72
95
  if (this.isTui) {
73
96
  const lines = message.split("\n");
74
97
  this.logLines.push(...lines);
75
- if (this.logLines.length > 1000) { // Limite de scrollbuffer
76
- this.logLines = this.logLines.slice(-1000);
98
+ if (this.logLines.length > MAX_LOG_SCROLLBUFFER) {
99
+ this.logLines = this.logLines.slice(-DASHBOARD_LOG_SLICE_LINES);
77
100
  }
78
101
  this.render();
79
102
  } else {
@@ -112,13 +135,8 @@ export class DashboardService {
112
135
  process.stdout.write(output);
113
136
  }
114
137
 
115
- private exit() {
116
- if (this.isTui) {
117
- process.stdout.write("\x1B[?1049l"); // Restore buffer
118
- process.stdout.write("\x1B[?25h"); // Show cursor
119
- process.stdin.setRawMode(false);
120
- process.stdin.pause();
121
- }
122
- process.exit(0);
138
+ private async exit() {
139
+ this.restoreTerminal();
140
+ await ProcessManager.getInstance().shutdown(0);
123
141
  }
124
142
  }