@archznn/xavva 1.7.0 → 1.8.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.
@@ -0,0 +1,78 @@
1
+ import { watch } from "fs";
2
+ import { Logger } from "../utils/ui";
3
+ import { DeployCommand } from "../commands/DeployCommand";
4
+ import type { AppConfig } from "../types/config";
5
+
6
+ export class WatcherService {
7
+ private isDeploying = false;
8
+ private pendingFullBuild = false;
9
+ private coolingFiles = new Set<string>();
10
+ private debounceTimer?: Timer;
11
+
12
+ constructor(private config: AppConfig, private deployCmd: DeployCommand) {}
13
+
14
+ public async start() {
15
+ await this.run(false);
16
+
17
+ watch(process.cwd(), { recursive: true }, async (event, filename) => {
18
+ if (!filename) return;
19
+
20
+ if (this.coolingFiles.has(filename)) return;
21
+ this.coolingFiles.add(filename);
22
+ setTimeout(() => this.coolingFiles.delete(filename), 500);
23
+
24
+ if (this.isIgnored(filename)) return;
25
+
26
+ const isBuildConfig = filename === "pom.xml" || filename === "build.gradle" || filename === "build.gradle.kts";
27
+ const isJava = filename.endsWith(".java") || isBuildConfig;
28
+ const isResource = this.isResourceFile(filename);
29
+
30
+ if (isBuildConfig) {
31
+ Logger.watcher(`Build configuration changed: ${filename}`, 'warn');
32
+ const { BuildCacheService } = await import("./BuildCacheService");
33
+ new BuildCacheService().clearCache();
34
+ this.pendingFullBuild = true;
35
+ }
36
+
37
+ if (isResource && !isJava) {
38
+ await this.deployCmd.syncResource(this.config, filename);
39
+ return;
40
+ }
41
+
42
+ if (!isJava) return;
43
+
44
+ Logger.watcher(filename, 'watch');
45
+ clearTimeout(this.debounceTimer);
46
+
47
+ this.debounceTimer = setTimeout(() => {
48
+ this.run(this.pendingFullBuild ? false : true);
49
+ this.pendingFullBuild = false;
50
+ }, 1000);
51
+ });
52
+ }
53
+
54
+ private async run(incremental = false) {
55
+ if (this.isDeploying) return;
56
+ this.isDeploying = true;
57
+ try {
58
+ await this.deployCmd.execute(this.config, { watch: true, incremental });
59
+ } catch (e) {
60
+ // Error handled by command
61
+ } finally {
62
+ this.isDeploying = false;
63
+ }
64
+ }
65
+
66
+ private isIgnored(filename: string): boolean {
67
+ return filename.includes("target") ||
68
+ filename.includes("build") ||
69
+ filename.includes("node_modules") ||
70
+ filename.split(/[/\\]/).some(part => part.startsWith("."));
71
+ }
72
+
73
+ private isResourceFile(filename: string): boolean {
74
+ return filename.endsWith(".jsp") || filename.endsWith(".html") ||
75
+ filename.endsWith(".css") || filename.endsWith(".js") ||
76
+ filename.endsWith(".xml") || filename.endsWith(".properties");
77
+ }
78
+ }
@@ -11,10 +11,12 @@ export interface ProjectConfig {
11
11
  profile: string;
12
12
  skipBuild: boolean;
13
13
  skipScan: boolean;
14
- cleanLogs: boolean;
14
+ clean: boolean;
15
15
  quiet: boolean;
16
16
  verbose: boolean;
17
17
  debug: boolean;
18
+ debugPort: number;
19
+ cleanLogs: boolean;
18
20
  grep?: string;
19
21
  }
20
22
 
@@ -22,3 +24,30 @@ export interface AppConfig {
22
24
  tomcat: TomcatConfig;
23
25
  project: ProjectConfig;
24
26
  }
27
+
28
+ export interface CLIArguments {
29
+ path?: string;
30
+ tool?: string;
31
+ name?: string;
32
+ port?: string;
33
+ "no-build"?: boolean;
34
+ scan?: boolean;
35
+ clean?: boolean;
36
+ quiet?: boolean;
37
+ help?: boolean;
38
+ version?: boolean;
39
+ debug?: boolean;
40
+ watch?: boolean;
41
+ profile?: string;
42
+ grep?: string;
43
+ verbose?: boolean;
44
+ dp?: string;
45
+ fix?: boolean;
46
+ incremental?: boolean;
47
+ }
48
+
49
+ export interface CommandContext {
50
+ config: AppConfig;
51
+ positionals: string[];
52
+ values: CLIArguments;
53
+ }
@@ -1,10 +1,10 @@
1
1
  import { parseArgs } from "util";
2
2
  import path from "path";
3
3
  import fs from "fs";
4
- import type { AppConfig } from "../types/config";
4
+ import type { AppConfig, CLIArguments, CommandContext } from "../types/config";
5
5
 
6
6
  export class ConfigManager {
7
- static async load(): Promise<{ config: AppConfig, positionals: string[], values: any }> {
7
+ static async load(): Promise<CommandContext> {
8
8
  const args = Bun.argv.slice(Bun.argv[0].endsWith("bun.exe") || Bun.argv[0].endsWith("bun") ? 2 : 1);
9
9
 
10
10
  const { values, positionals } = parseArgs({
@@ -25,12 +25,14 @@ export class ConfigManager {
25
25
  profile: { type: "string", short: "P" },
26
26
  grep: { type: "string", short: "G" },
27
27
  verbose: { type: "boolean", short: "V" },
28
+ dp: { type: "string" },
28
29
  fix: { type: "boolean" },
29
30
  },
30
31
  strict: false,
31
32
  allowPositionals: true,
32
33
  });
33
34
 
35
+ const cliValues = values as CLIArguments;
34
36
  const isDev = positionals.includes("dev");
35
37
  const isRun = positionals.includes("run") || positionals.includes("debug");
36
38
 
@@ -47,30 +49,32 @@ export class ConfigManager {
47
49
 
48
50
  const config: AppConfig = {
49
51
  tomcat: {
50
- path: String(values.path || envTomcatPath),
51
- port: parseInt(String(values.port || "8080")),
52
+ path: String(cliValues.path || envTomcatPath),
53
+ port: parseInt(String(cliValues.port || "8080")),
52
54
  webapps: "webapps",
53
- grep: values.grep ? String(values.grep) : "",
55
+ grep: cliValues.grep ? String(cliValues.grep) : "",
54
56
  },
55
57
  project: {
56
- appName: values.name ? String(values.name) : "",
57
- buildTool: (values.tool as "maven" | "gradle") || detectedTool,
58
- profile: String(values.profile || ""),
59
- skipBuild: !!values["no-build"],
60
- skipScan: values.scan !== undefined ? !values.scan : true,
61
- cleanLogs: !!(values.clean || isDev),
62
- quiet: !!(values.quiet || isDev),
63
- verbose: !!values.verbose,
64
- debug: !!(values.debug || isDev || isRun),
65
- grep: runClass || (values.grep ? String(values.grep) : ""),
58
+ appName: cliValues.name ? String(cliValues.name) : "",
59
+ buildTool: (cliValues.tool as "maven" | "gradle") || detectedTool,
60
+ profile: String(cliValues.profile || ""),
61
+ skipBuild: !!cliValues["no-build"],
62
+ skipScan: cliValues.scan !== undefined ? !cliValues.scan : true,
63
+ clean: !!cliValues.clean,
64
+ cleanLogs: cliValues.verbose ? false : true,
65
+ quiet: cliValues.verbose ? false : true,
66
+ verbose: !!cliValues.verbose,
67
+ debug: !!(cliValues.debug || isDev || isRun),
68
+ debugPort: parseInt(String(cliValues.dp || "5005")),
69
+ grep: runClass || (cliValues.grep ? String(cliValues.grep) : ""),
66
70
  }
67
71
  };
68
72
 
69
- if (isDev) values.watch = true;
73
+ if (isDev) cliValues.watch = true;
70
74
 
71
75
  this.ensureGitIgnore();
72
76
 
73
- return { config, positionals, values };
77
+ return { config, positionals, values: cliValues };
74
78
  }
75
79
 
76
80
  private static detectBuildTool(): "maven" | "gradle" {
package/src/utils/ui.ts CHANGED
@@ -54,21 +54,21 @@ export class Logger {
54
54
  static banner(command?: string) {
55
55
  console.clear();
56
56
  const git = this.getGitContext();
57
- const name = (process.cwd().split(/[/\\]/).pop() || "JAVA").toUpperCase();
57
+ const name = (process.cwd().split(/[/\\]/).pop() || "PROJECT").toUpperCase();
58
+ const version = `v${pkg.version}`;
58
59
 
59
- const width = 62;
60
- const line = "".repeat(width);
61
-
62
- this.write(`${this.C.gray}╭${line}╮`);
63
- this.write(`${this.C.gray}│ ${this.C.bold}${this.C.blue}${name} CLI${this.C.reset}${" ".repeat(width - name.length - 6)} ${this.C.gray}│`);
60
+ const mode = command?.toUpperCase() || "DEPLOY";
61
+ const modeColor = mode === "DEV" ? this.C.green : this.C.blue;
62
+ const modeIcon = mode === "DEV" ? "⚡" : "🚀";
63
+
64
+ console.log("");
65
+ console.log(` ${this.C.bold}${this.C.cyan}X A V V A${this.C.reset} ${this.C.dim}─${this.C.reset} ${this.C.bold}${this.C.white}${name}${this.C.reset}`);
64
66
 
65
- const info = `Version: ${pkg.version} | Branch: ${git.branch} | ${git.hash}`;
66
- this.write(`${this.C.gray} ${this.C.dim}${info}${" ".repeat(width - info.length - 2)}${this.C.gray}│`);
67
+ const gitInfo = git.branch ? `${this.C.magenta}🌿 ${git.branch}${this.C.reset} ${this.C.dim}•${this.C.reset} ${this.C.yellow}${git.hash}${this.C.reset}` : "";
68
+ console.log(` ${this.C.dim}📦 ${version}${gitInfo ? ` ${this.C.dim}•${this.C.reset} ${gitInfo}` : ""}${this.C.reset}`);
67
69
 
68
- const modeLine = `Mode: ${command?.toUpperCase() || "DEPLOY"}`;
69
- const status = command === 'dev' ? `${this.C.green}🟢` : `${this.C.blue}🔵`;
70
- this.write(`${this.C.gray}│ ${this.C.yellow}${this.C.bold}${modeLine}${" ".repeat(width - modeLine.length - 5)}${status} ${this.C.gray}│`);
71
- this.write(`${this.C.gray}╰${line}╯${this.C.reset}`);
70
+ console.log(` ${modeColor}${this.C.bold}⬢ ${modeIcon} ${mode} MODE${this.C.reset}`);
71
+ console.log(` ${this.C.dim}─────────────────────────────────────────────────${this.C.reset}`);
72
72
  }
73
73
 
74
74
  static section(title: string) {
@@ -162,7 +162,9 @@ export class Logger {
162
162
  "org.apache.catalina.core.StandardContext.setPath", "milliseconds",
163
163
  "org.apache.catalina.startup.HostConfig.deployWAR", "org.apache.catalina.startup.HostConfig.deployDirectory",
164
164
  "Deployment of web application", "Deploying web application archive", "at org.apache",
165
- "Registering directory"
165
+ "Registering directory", "initialized in ClassLoader", "Discovered plugins:",
166
+ "enhanced with plugin initialization", "registerJerseyContainer", "JasperLoader@",
167
+ "Hotswap ready (Plugins:", "autoHotswap.delay", "watchResources=false"
166
168
  ];
167
169
  return noise.some(n => line.includes(n));
168
170
  }