Skip to content

Commit 8bab367

Browse files
committed
refactor: refactor all cli
1 parent 0d354c3 commit 8bab367

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1230
-1187
lines changed

src/action/abstract.action.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,55 @@
11
import { type Input } from "@lib/input";
2+
import { Prefixes } from "@lib/ui";
3+
4+
import { handleActionError } from "@utils/errors";
5+
6+
export interface HandleResult {
7+
success?: boolean;
8+
keepAlive?: boolean;
9+
}
210

311
export abstract class AbstractAction {
4-
public abstract handle(args?: Input, options?: Input, extraFlags?: string[]): Promise<void>;
12+
protected abstract startMessage: string;
13+
protected abstract successMessage: string;
14+
protected abstract failureMessage: string;
15+
16+
public abstract handle(
17+
args?: Input,
18+
options?: Input,
19+
extraFlags?: string[],
20+
): Promise<HandleResult>;
21+
22+
public async run(args?: Input, options?: Input, extraFlags?: string[]): Promise<void> {
23+
this.logStart();
24+
25+
try {
26+
const result = await this.handle(args, options, extraFlags);
27+
this.resolveResult(result);
28+
} catch (error: unknown) {
29+
handleActionError(this.failureMessage, error);
30+
}
31+
}
32+
33+
private logStart(): void {
34+
console.info();
35+
console.info(`${Prefixes.INFO} ${this.startMessage}`);
36+
console.info();
37+
}
38+
39+
private resolveResult(result: HandleResult): void {
40+
const success = result?.success !== false;
41+
const keepAlive = result?.keepAlive === true;
42+
43+
if (keepAlive) return;
44+
45+
console.info();
46+
47+
if (!success) {
48+
if (this.failureMessage) console.error(this.failureMessage);
49+
process.exit(1);
50+
}
51+
52+
if (this.successMessage) console.info(this.successMessage);
53+
process.exit(0);
54+
}
555
}

src/action/actions/build.action.ts

Lines changed: 106 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,134 @@
1-
import * as ansis from "ansis";
21
import { watch } from "chokidar";
3-
import * as console from "node:console";
4-
import { dirname, join } from "path";
2+
import { dirname, join } from "node:path";
53

6-
import { type BuildConfig } from "@lib/config";
7-
import { type Input, getDirectoryInput } from "@lib/input";
8-
import { getWatchInput } from "@lib/input";
9-
import { PackageManager, PackageManagerFactory } from "@lib/package-manager";
4+
import { type BuildConfig, type Config } from "@lib/config";
5+
import { type Input, getDirectoryInput, getWatchInput } from "@lib/input";
6+
import { PackageManagerFactory, PackageManagerName } from "@lib/package-manager";
107
import { Messages } from "@lib/ui";
118

129
import { getCwd } from "@utils/path";
10+
import { runSafe } from "@utils/run-safe";
1311

1412
import { getConfig } from "~/action/common/config";
1513

16-
import { AbstractAction } from "../abstract.action";
14+
import { AbstractAction, type HandleResult } from "../abstract.action";
1715

18-
interface BuildPart {
16+
interface BuildTarget {
17+
name: string;
1918
entry: string;
2019
output: string;
21-
target: "client" | "server";
20+
platform: "browser" | "node";
2221
}
2322

2423
export class BuildAction extends AbstractAction {
25-
public async handle(_args: Input, options: Input) {
26-
console.info(Messages.BUILD_START);
27-
console.info();
24+
protected startMessage = Messages.BUILD_START;
25+
protected successMessage = Messages.BUILD_SUCCESS;
26+
protected failureMessage = Messages.BUILD_FAILED;
27+
28+
public async handle(_args: Input, options: Input): Promise<HandleResult> {
29+
const directory = getDirectoryInput(options);
30+
const config = await getConfig(options, directory);
31+
const isWatch = getWatchInput(options);
32+
33+
const targets = this.resolveTargets(config, options);
34+
const results = await this.buildAll(targets, directory, isWatch);
2835

29-
try {
30-
const directory = getDirectoryInput(options);
31-
const config = await getConfig(options, directory);
32-
const watch = getWatchInput(options);
36+
if (isWatch) {
37+
return this.enterWatchMode();
38+
}
39+
40+
return { success: results.every(Boolean) };
41+
}
3342

34-
const client = getPart(
43+
private resolveTargets(config: Config, options: Input): BuildTarget[] {
44+
const targets: BuildTarget[] = [
45+
this.createTarget(
46+
"Client",
3547
config.client.build,
48+
"browser",
3649
options.get("clientDirectory")?.value as string | undefined,
37-
"client",
38-
);
39-
let res = await buildPart("Client", client, directory, { watch });
50+
),
51+
];
4052

41-
if (config.server.enable) {
42-
const server = getPart(
53+
if (config.server.enable) {
54+
targets.push(
55+
this.createTarget(
56+
"Server",
4357
config.server.build,
58+
"node",
4459
options.get("serverDirectory")?.value as string | undefined,
45-
"server",
46-
);
47-
res = (await buildPart("Server", server, directory, { watch })) ? res : false;
48-
}
49-
50-
console.info();
51-
52-
if (watch) {
53-
console.info(Messages.BUILD_WATCH_START);
54-
console.info();
55-
return;
56-
}
57-
58-
if (!res) {
59-
console.info(Messages.BUILD_FAILED);
60-
process.exit(1);
61-
}
62-
console.info(Messages.BUILD_SUCCESS);
63-
process.exit(0);
64-
} catch (e) {
65-
console.error(e);
66-
process.exit(1);
60+
),
61+
);
6762
}
63+
64+
return targets;
65+
}
66+
67+
private createTarget(
68+
name: string,
69+
config: BuildConfig,
70+
platform: "browser" | "node",
71+
outDirOverride?: string,
72+
): BuildTarget {
73+
return {
74+
name,
75+
entry: config.entryFile,
76+
output: outDirOverride || config.outDir,
77+
platform,
78+
};
6879
}
69-
}
7080

71-
const getPart = (
72-
config: BuildConfig,
73-
directoryOption: string | undefined,
74-
target: "client" | "server",
75-
): BuildPart => {
76-
return {
77-
entry: config.entryFile,
78-
output: directoryOption || config.outDir,
79-
target: target,
80-
};
81-
};
82-
83-
const buildPart = async (
84-
name: string,
85-
part: BuildPart,
86-
directory: string,
87-
options?: { watch?: boolean },
88-
) => {
89-
const packageManagerName = PackageManager.LOCAL_BUN;
90-
91-
const packageManager = PackageManagerFactory.create(packageManagerName);
92-
93-
const build = async (watch = false) => {
94-
try {
95-
return await packageManager.build(
96-
name,
97-
directory,
98-
part.entry,
99-
part.output,
100-
[
101-
"--asset-naming",
102-
"[name].[ext]",
103-
"--target",
104-
part.target === "client" ? "browser" : "node",
105-
],
106-
watch,
81+
private async buildAll(
82+
targets: BuildTarget[],
83+
directory: string,
84+
isWatch: boolean,
85+
): Promise<boolean[]> {
86+
const results: boolean[] = [];
87+
for (const target of targets) {
88+
const result = await this.buildTarget(target, directory, isWatch);
89+
results.push(result);
90+
}
91+
return results;
92+
}
93+
94+
private async buildTarget(
95+
target: BuildTarget,
96+
directory: string,
97+
isWatch: boolean,
98+
): Promise<boolean> {
99+
const packageManager = PackageManagerFactory.create(PackageManagerName.LOCAL_BUN);
100+
101+
const executeBuild = (rebuild = false) =>
102+
runSafe(
103+
() =>
104+
packageManager.build(
105+
target.name,
106+
directory,
107+
target.entry,
108+
target.output,
109+
["--asset-naming", "[name].[ext]", "--target", target.platform],
110+
rebuild,
111+
),
112+
false,
107113
);
108-
} catch (error: any) {
109-
if (error && error.message) {
110-
console.error(ansis.red(error.message));
111-
}
112-
return false;
114+
115+
if (isWatch) {
116+
this.watchDirectory(directory, target.entry, () => executeBuild(true));
113117
}
114-
};
115118

116-
if (options?.watch)
117-
watch(dirname(join(getCwd(directory), part.entry))).on("change", () => build(true));
119+
const result = await executeBuild();
120+
return result !== false;
121+
}
118122

119-
return await build();
120-
};
123+
private watchDirectory(directory: string, entry: string, onChange: () => void): void {
124+
const watchPath = dirname(join(getCwd(directory), entry));
125+
watch(watchPath).on("change", onChange);
126+
}
127+
128+
private enterWatchMode(): HandleResult {
129+
console.info();
130+
console.info(Messages.BUILD_WATCH_START);
131+
console.info();
132+
return { keepAlive: true };
133+
}
134+
}

src/action/actions/dev.action.ts

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,47 @@
1-
import * as ansis from "ansis";
2-
31
import { type Input, getDevGenerateInput, getDirectoryInput } from "@lib/input";
42
import { PackageManagerFactory } from "@lib/package-manager";
53
import { Messages } from "@lib/ui";
64

7-
import { AbstractAction } from "../abstract.action";
5+
import { runSafe } from "@utils/run-safe";
6+
7+
import { AbstractAction, type HandleResult } from "../abstract.action";
88

99
export class DevAction extends AbstractAction {
10-
public async handle(_args: Input, options: Input) {
11-
console.info(Messages.DEV_START);
12-
console.info();
13-
14-
try {
15-
const directory = getDirectoryInput(options);
16-
const generate = getDevGenerateInput(options);
17-
18-
await Promise.all([
19-
generate ? runAction("generate", [], directory, false) : undefined,
20-
runAction("build", [], directory, false),
21-
runAction("start", [], directory, true),
22-
]);
23-
24-
console.info(Messages.DEV_SUCCESS);
25-
process.exit(0);
26-
} catch (e) {
27-
console.error(Messages.DEV_FAILED);
28-
console.error(e);
29-
process.exit(1);
30-
}
10+
protected startMessage = Messages.DEV_START;
11+
protected successMessage = Messages.DEV_SUCCESS;
12+
protected failureMessage = Messages.DEV_FAILED;
13+
14+
public async handle(_args: Input, options: Input): Promise<HandleResult> {
15+
const directory = getDirectoryInput(options);
16+
const generate = getDevGenerateInput(options);
17+
18+
const tasks = this.buildTaskList(directory, generate);
19+
await Promise.all(tasks);
20+
21+
return { keepAlive: true };
3122
}
32-
}
3323

34-
const runAction = async (
35-
command: string,
36-
params: string[],
37-
directory: string,
38-
stdout: boolean = false,
39-
) => {
40-
try {
41-
const packageManager = await PackageManagerFactory.find(directory);
42-
await packageManager.runDev(directory, "nf", {}, [command, ...params, "--watch"], !stdout);
43-
} catch (error: any) {
44-
if (error && error.message) {
45-
console.error(ansis.red(error.message));
24+
private buildTaskList(directory: string, generate: boolean): Promise<void>[] {
25+
const tasks: Promise<void>[] = [];
26+
27+
if (generate) {
28+
tasks.push(this.runSubCommand("generate", directory, { silent: true }));
4629
}
30+
31+
tasks.push(this.runSubCommand("build", directory, { silent: true }));
32+
tasks.push(this.runSubCommand("start", directory, { silent: false }));
33+
34+
return tasks;
4735
}
48-
};
36+
37+
private async runSubCommand(
38+
command: string,
39+
directory: string,
40+
options: { silent: boolean },
41+
): Promise<void> {
42+
await runSafe(async () => {
43+
const packageManager = await PackageManagerFactory.find(directory);
44+
await packageManager.runDev(directory, "nf", {}, [command, "--watch"], options.silent);
45+
});
46+
}
47+
}

0 commit comments

Comments
 (0)